<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Código Metrópoli - Blog de programación &#187; Proyectos</title>
	<atom:link href="http://www.codigometropoli.com/category/proyectos/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.codigometropoli.com</link>
	<description>Programación para Super Héroes</description>
	<lastBuildDate>Wed, 27 Apr 2011 07:20:01 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0.1</generator>
		<item>
		<title>Sistema de Gastos en Flex con AMFPHP y MySQL</title>
		<link>http://www.codigometropoli.com/sistema-de-gastos-en-flex-con-amfphp-y-mysql/</link>
		<comments>http://www.codigometropoli.com/sistema-de-gastos-en-flex-con-amfphp-y-mysql/#comments</comments>
		<pubDate>Tue, 28 Oct 2008 16:30:48 +0000</pubDate>
		<dc:creator>Carla Macías</dc:creator>
				<category><![CDATA[Flex]]></category>
		<category><![CDATA[Proyectos]]></category>
		<category><![CDATA[AMFPHP]]></category>
		<category><![CDATA[MySQL]]></category>

		<guid isPermaLink="false">http://www.codigometropoli.com/?p=472</guid>
		<description><![CDATA[En este tutorial veremos cómo acceder a los registros de una base de datos MySQL desde Flex utilizando AMFPHP. Realizaremos un pequeño Sistema de Gastos en el cual haremos inserciones a la base de datos, consultas, modificaciones y eliminación de registros. Si no sabes qué es y para qué sirve el AMFPHP, visita nuestro tutorial [...]]]></description>
			<content:encoded><![CDATA[<p><img class="alignright" style="float: right;" src="http://codigometropoli.com/images/flex.png" alt="Flex" width="93" height="93" />En este tutorial veremos cómo acceder a los registros de una base de datos MySQL desde Flex utilizando <a href="http://www.amfphp.org/" target="_blank">AMFPHP</a>. Realizaremos un pequeño Sistema de Gastos en el cual haremos inserciones a la base de datos, consultas, modificaciones y eliminación de registros. Si no sabes qué es y para qué sirve el AMFPHP, visita nuestro tutorial de <a href="http://www.codigometropoli.com/introduccion-a-amfphp/" target="_self">Introducción a AMFPHP</a>.</p>
<p><span id="more-472"></span></p>
<p>En esta ocasión no veremos a detalle todo el código que involucra el sistema; sin embargo, puedes encontrar al final de esta entrada los archivos fuentes.<br />
El sistema funciona de la siguiente manera:<br />
- El usuario primero da de alta tipo de monedas en la Sección de Divisas (Su nombre y símbolo).<br />
- Posteriormente el usuario puede dar de alta servicios en la Sección de Servicios (valga la redundancia). Estos servicios son opcionales y pueden seleccionarse cuando un usuario introduce un gasto en el sistema. Ejemplo de servicios: teléfono, gas, luz, educación, restaurantes, entretenimiento, etc.<br />
- Dentro del sistema, el usuario puede dar de alta gastos e ingresos. Estos gastos o ingresos requieren de la fecha, cantidad y divisa con la cual se realizó la operación. De manera opcional se puede introducir un concepto (descripción) y se puede seleccionar un servicio (si se trata de un gasto).</p>
<p>Comenzaremos con el script de nuestra base de datos:</p>
<pre class="brush: sql;">
# Host: localhost    Database: codmetr_gastos
# ------------------------------------------------------
# Server version 4.1.22-community-nt

#
# Table structure for table tbldivisa
#
CREATE TABLE `tbldivisa` (
  `INTNUMDIVISA` int(11) NOT NULL auto_increment,
  `STRNOMBRE` varchar(30) NOT NULL default '',
  `STRSIMBOLO` varchar(5) character set utf8 default NULL,
  PRIMARY KEY  (`INTNUMDIVISA`)
) ENGINE=MyISAM AUTO_INCREMENT=3 DEFAULT CHARSET=latin1;

#
# Table structure for table tbloperacion
#
CREATE TABLE `tbloperacion` (
  `INTNUMOPERACION` int(11) NOT NULL auto_increment,
  `DTMFECHA` date NOT NULL default '0000-00-00',
  `STRCONCEPTO` varchar(100) default NULL,
  `NUMCANTIDAD` decimal(10,2) default NULL,
  `INTNUMDIVISA` int(11) NOT NULL default '0',
  `INTNUMSERVICIO` int(11) default NULL,
  `INTOPERACION` int(11) NOT NULL default '0',
  PRIMARY KEY  (`INTNUMOPERACION`)
) ENGINE=MyISAM AUTO_INCREMENT=4 DEFAULT CHARSET=latin1;

#
# Table structure for table tblservicio
#
CREATE TABLE `tblservicio` (
  `INTNUMSERVICIO` int(11) NOT NULL auto_increment,
  `STRNOMBRE` varchar(50) default NULL,
  PRIMARY KEY  (`INTNUMSERVICIO`)
) ENGINE=MyISAM AUTO_INCREMENT=3 DEFAULT CHARSET=latin1;
</pre>
<p>Del código anterior podemos observar que tenemos una tabla <strong>tbldivisa</strong>, en la cual almacenamos los tipos de moneda que utilizamos. Una tabla <strong>tblservicio</strong> donde guardamos los servicios ingresados; y una tabla <strong>tbloperacion</strong> en donde almacenamos las operaciones (gastos e ingresos). Las relaciones entre divisas y servicios con respecto a las operaciones están dadas por el ID de estas tablas (INTNUMDIVISA e INTNUMSERVICIO).</p>
<p>Ahora veremos el código PHP de nuestra que funcionará como servicio:</p>
<pre class="brush: php;">
&lt;?php
class SistemaGastos
{
	var $sqlstring = &quot;&quot;;
	var $server = &quot;localhost&quot;;
	var $user =  &quot;usuario_database&quot;;
	var $pass = &quot;contrasena_database&quot;;
	var $database = &quot;codigometr_gastos&quot;;

	var $db = 0;
	var $rs = 0;
	var $row = 0;
	var $recordcount = 0;
	var $EOF = true;

	function _conectarBaseDatos()
	{
		 $this-&gt;db = mysql_connect($this-&gt;server,$this-&gt;user,$this-&gt;pass);
   		 mysql_select_db($this-&gt;database,$this-&gt;db) or die(mysql_error());
	}

	function _ejecutarQuery($strSql)
	{
    		$this-&gt;sqlstring = $strSql;
	    	$this-&gt;_exec_command();
		return $this-&gt;lastid;
    	}

	function _exec_command()
	{
		if ($this-&gt;db &amp;&amp; $this-&gt;sqlstring!=&quot;&quot;)
		{
			$this-&gt;rs = mysql_query($this-&gt;sqlstring,$this-&gt;db);
			if ($this-&gt;rs)
			{
				$this-&gt;EOF = true;
				$this-&gt;recordcount = mysql_affected_rows();
				$this-&gt;lastid = mysql_insert_id();
			}
			else
			{
				$this-&gt;recordcount = 0;
				$this-&gt;EOF = true;
			}
		}
		else
		{
			$this-&gt;recordcount = 0;
			$this-&gt;EOF = true;
		}
	}	

	function _destruir()
	{
    		if($this-&gt;db)
			mysql_close($this-&gt;db);
	}

	/* Métodos para la tabla tbldivisa */
	function insertarDivisa($nombre, $simbolo)
	{
		$this-&gt;_conectarBaseDatos();
		$sql = &quot;Insert into `tbldivisa` (`STRNOMBRE`, `STRSIMBOLO`) VALUES ('&quot; . $nombre . &quot;', '&quot; . $simbolo . &quot;')&quot;;
		$this-&gt;_ejecutarQuery($sql);
		$this-&gt;_destruir();
	}

	function modificarDivisa($idDivisa, $nombre, $simbolo)
	{
		$this-&gt;_conectarBaseDatos();
		$sql = &quot;Update `tbldivisa` set `STRNOMBRE` = '&quot; . $nombre . &quot;', `STRSIMBOLO` = '&quot; . $simbolo . &quot;' where `INTNUMDIVISA` = &quot; . $idDivisa;
		$this-&gt;_ejecutarQuery($sql);
		$this-&gt;_destruir();
	}

	function eliminarDivisa($idDivisa)
	{
		$this-&gt;_conectarBaseDatos();
		$sql = &quot;Delete from `tbldivisa` where `INTNUMDIVISA`= &quot; . $idDivisa;
		$result = mysql_query($sql);
		$sql = &quot;Delete from `tbloperacion` where `INTNUMDIVISA`= &quot; . $idDivisa;
		mysql_query($sql);
		$this-&gt;_destruir();
		return $result;
	}

	function obtenerDivisas()
	{
		$this-&gt;_conectarBaseDatos();
		$sql = &quot;Select INTNUMDIVISA, STRNOMBRE, STRSIMBOLO from tbldivisa ORDER BY STRNOMBRE asc&quot;;
		$result = mysql_query($sql);

		while ($row = mysql_fetch_object($result))
		{
			$divisas[] = $row;
		}	

		$this-&gt;_destruir();

		return($divisas);
	}

	/* Métodos para la tabla tblservicio */
	function insertarServicio($nombre)
	{
		$this-&gt;_conectarBaseDatos();
		$sql = &quot;Insert into `tblservicio` (`STRNOMBRE`) VALUES ('&quot; . $nombre . &quot;')&quot;;
		$this-&gt;_ejecutarQuery($sql);
		$this-&gt;_destruir();
	}

	function modificarServicio($idServicio, $nombre)
	{
		$this-&gt;_conectarBaseDatos();
		$sql = &quot;Update `tblservicio` set `STRNOMBRE` = '&quot; . $nombre . &quot;' where `INTNUMSERVICIO` = &quot; . $idServicio;
		$this-&gt;_ejecutarQuery($sql);
		$this-&gt;_destruir();
	}

	function eliminarServicio($idServicio)
	{
		$this-&gt;_conectarBaseDatos();
		$sql = &quot;Delete from `tblservicio` where `INTNUMSERVICIO`= &quot; . $idServicio;
		$result = mysql_query($sql);
		$sql = &quot;Delete from `tbloperacion` where `INTNUMSERVICIO`= &quot; . $idServicio;
		mysql_query($sql);
		$this-&gt;_destruir();
		return $result;
	}

	function obtenerServicios()
	{
		$this-&gt;_conectarBaseDatos();
		$sql = &quot;Select INTNUMSERVICIO, STRNOMBRE from tblservicio ORDER BY STRNOMBRE asc&quot;;
		$result = mysql_query($sql);

		while ($row = mysql_fetch_object($result))
		{
			$servicios[] = $row;
		}	

		$this-&gt;_destruir();

		return($servicios);
	}

	/* Métodos para la tabla tbloperacion */
	function insertarOperacion($fecha, $concepto, $cantidad, $id_divisa, $servicio, $operacion)
	{
		$this-&gt;_conectarBaseDatos();
		$sql = &quot;INSERT INTO `tbloperacion` (DTMFECHA, STRCONCEPTO, NUMCANTIDAD, INTNUMDIVISA, INTNUMSERVICIO, INTOPERACION) VALUES ('&quot; . $fecha . &quot;','&quot; . $concepto . &quot;',&quot; . $cantidad . &quot;,&quot; . $id_divisa . &quot;,&quot; . $servicio . &quot;,&quot; . $operacion . &quot;)&quot;;
		$result = $this-&gt;_ejecutarQuery($sql);
		$this-&gt;_destruir();

		return $result;
	}

	function actualizarOperacion($idOperacion, $fecha, $concepto, $cantidad, $id_divisa, $servicio, $operacion)
	{
		$this-&gt;_conectarBaseDatos();
		$sql = &quot;Update `tbloperacion` set `DTMFECHA` = '&quot; . $fecha . &quot;', `STRCONCEPTO` = '&quot; . $concepto . &quot;', `NUMCANTIDAD` = &quot; . $cantidad . &quot;, `INTNUMDIVISA` = &quot; . $id_divisa . &quot;, `INTNUMSERVICIO` = &quot; . $servicio . &quot;, `INTOPERACION` = &quot; . $operacion . &quot; where `INTNUMOPERACION` = &quot; . $idOperacion;
		$result = $this-&gt;_ejecutarQuery($sql);
		$this-&gt;_destruir();
		return $result;
	}

	function eliminarOperacion($idOperacion)
	{
		$this-&gt;_conectarBaseDatos();
		$sql = &quot;Delete from `tbloperacion` where `INTNUMOPERACION`= &quot; . $idOperacion;
		$result = mysql_query($sql);
		$this-&gt;_destruir();
		return $result;
	}

	function obtenerOperaciones()
	{
		$this-&gt;_conectarBaseDatos();
		$sql = &quot;Select * from `tbloperacion` ORDER BY DTMFECHA asc&quot;;
		$result = mysql_query($sql);

		while ($row = mysql_fetch_object($result))
		{
			$operaciones[] = $row;
		}	

		$this-&gt;_destruir();

		return($operaciones);
	}

	function realizarConsulta($servicio, $divisa, $concepto, $fecha1, $fecha2, $cantidad1, $cantidad2, $operacion)
	{
		$this-&gt;_conectarBaseDatos();
		$sql = &quot;Select top.DTMFECHA, top.STRCONCEPTO, top.NUMCANTIDAD, top.INTNUMDIVISA, top.INTNUMSERVICIO, top.INTOPERACION, td.STRNOMBRE, td.STRSIMBOLO FROM tbloperacion AS top, tbldivisa as td WHERE td.INTNUMDIVISA = top.INTNUMDIVISA&quot;;

		/* Selección Concepto */
		if($concepto != &quot;&quot;)
			$sql .= &quot; AND top.STRCONCEPTO LIKE '%&quot; . $concepto . &quot;%'&quot;;

		/* Selección Divisa */
		if($divisa != 0) {
			$sql .= &quot; AND top.INTNUMDIVISA = &quot; . $divisa . &quot; AND td.INTNUMDIVISA = &quot; . $divisa;
		}

		/* Selección Servicio */
		if($servicio != 0) {
			$sql .= &quot; AND top.INTNUMSERVICIO = &quot; . $servicio;
		}

		if($cantidad1 != &quot;&quot; &amp;&amp; $cantidad2 != &quot;&quot;)
		{
			if($cantidad1 &lt;= $cantidad2)
				$sql .= &quot; AND top.NUMCANTIDAD BETWEEN &quot; . $cantidad1 . &quot; AND &quot; . $cantidad2;
			else
				$sql .= &quot; AND top.NUMCANTIDADBETWEEN &quot; . $cantidad2 . &quot; AND &quot; . $cantidad1;
		}
		else if($cantidad1 != &quot;&quot;)
			$sql .= &quot; AND top.NUMCANTIDAD = &quot; . $cantidad1;
		else if($cantidad2 != &quot;&quot;)
			$sql .= &quot; AND top.NUMCANTIDAD = &quot; . $cantidad2;

		/* Selección Operación */
		if($operacion == 3)
			$sql .= &quot; AND top.INTOPERACION &gt;= 1 AND top.INTOPERACION &lt;= 2&quot;;
		else
			$sql .= &quot; AND top.INTOPERACION = &quot;  . $operacion;		

		if($fecha1 != NULL || $fecha2 != NULL)
		{
			if($fecha1 != &quot;&quot; &amp;&amp; $fecha2 == &quot;&quot;)
			{
				$sql .= &quot; AND top.DTMFECHA = '&quot; . $fecha1 . &quot;'&quot;;
			}
			else
			{
				$sql .= &quot; AND top.DTMFECHA &gt;= '&quot; . $fecha1 . &quot;' AND top.DTMFECHA &lt;= '&quot; . $fecha2 . &quot;'&quot;;
			}
		}

		$sql .= &quot; ORDER BY top.DTMFECHA asc, top.NUMCANTIDAD asc&quot;;
		$result = mysql_query($sql);

		while ($row = mysql_fetch_object($result))
		{
			$registros[] = $row;
		}	

		$this-&gt;_destruir();

		return($registros);
	}
}
?&gt;
</pre>
<p>Los métodos que inician con guión bajo (_) son métodos privados y por lo tanto no podemos acceder a ellos desde Flex. Los otros métodos <em>insertarDivisa</em>, <em>modificarDivisa</em>, <em>eliminarDivisa</em>, <em>obtenerDivisas</em>, etc. son métodos públicos a los cuales accedemos desde Flex.<br />
Observa cómo en los métodos obtenerXXX almacenamos los registros en un arreglo y lo regresamos a nuestra aplicación. Los queries en realidad son muy sencillos, por lo que no requieren explicación; solamente observa cómo en los métodos <strong>eliminarServicio</strong> y <strong>eliminarDivisa</strong> hacemos el borrado de los registros que involucran estos registros en la tabla <em>tbloperacion</em>. Esto es para evitar que haya inconsistencia en la base de datos.</p>
<p>Ahora veremos el código principal de nuestra aplicación en Flex.<br />
Para poder hacer uso del AMFPHP necesitamos de las librerías <strong>NetConnection</strong> y <strong>Responder</strong>.</p>
<pre class="brush: as3;">
	import flash.net.NetConnection;
	import flash.net.Responder;
</pre>
<p>Para poder acceder a los servicios en AMFPHP debemos especificar la ruta en la cual se encuentra el archivo gateway.php de AMFPHP:</p>
<pre class="brush: as3;">
	private var gateway:String = &quot;http://www.codigometropoli.com/wp-content/uploads/2008/10/SistemaGastos/AMFPHP1.9/gateway.php&quot;;
	private var connection:NetConnection;
	private var responder:Responder;
</pre>
<p>Al iniciar la aplicación debemos llamar a la función <em>connect</em> pasándole como parámetro el <em>gateway</em>:</p>
<pre class="brush: as3;">
function iniciaAplicacion()
{
	connection = new NetConnection;
	connection.connect(gateway);
}
</pre>
<p>Dentro del constructor de la clase Responder debemos especificar las funciones que se ejecutarán en caso de que la llamada haya sido sido exitosa y en caso de que haya existido un error. Para hacer la llamada al servicio utilizamos la función <em>call</em>; a la cual pasamos como parámetro el nombre de la función que queremos llamar y que se encuentra en la clase <strong>SistemaGastos.php</strong>, nuestro objeto de la clase Responder y los parámetros que debemos pasarle a la función:</p>
<pre class="brush: as3;">
responder = new Responder(insertarOperacionResult, errorConsulta);
connection.call(&quot;SistemaGastos.insertarOperacion&quot;, responder, param1, param2, param3...);
</pre>
<p>Del código anterior podemos deducir que el nombre de nuestra clase en PHP es <strong>SistemaGastos</strong> y que tiene un método público llamado <strong>insertarOperacion</strong>.</p>
<p>En caso de que la llamada haya sido exitosa, se ejecutará el método <em>insertarOperacionResult</em>:</p>
<pre class="brush: as3;">
private function insertarOperacionResult(result:Object):void {
	if(result.toString() != &quot;0&quot;)
	{
		restablecerForma();
		Alert.show(&quot;Registro almacenado&quot;, &quot;Aviso&quot;);
	}
	else
		Alert.show(&quot;No se pudo almacenar el registro&quot;, &quot;Error&quot;);
}
</pre>
<p>En caso contrario, si existiera algún error en la llamada al servicio, la función <em>errorConsulta</em> se ejecutará:</p>
<pre class="brush: as3;">
private function errorConsulta(fault:Object):void {
	Alert.show(fault.description, &quot;Error&quot;);
	CursorManager.removeBusyCursor();
}
</pre>
<p>Nuestra forma de alta de operación (Gasto o Ingreso) será la siguiente:</p>
<div align="center"><img src="http://www.codigometropoli.com/images/screens/sistema_gastos_flex_alta.jpg" alt="Formulario de alta de gastos o ingresos" /></div>
<p>De la imagen anterior puedes saber qué tipo de información estamos solicitando, cuál es la obligatoria (Fecha, Cantidad y Divisa), así como la forma en qué estamos mostrando al usuario las divisas y servicios dados de alta (por medio de ComboBox).</p>
<p>Las partes de código mostradas forman parte de la llamada a una función que se encarga de insertar un registro. El código no tendrá variación cuando se trate de modificar un registro; y cuando se trate de eliminar un registro solamente le pasaremos el ID del registro a eliminar. ¿Pero qué pasa cuando se trata de una consulta? ¿Cómo obtenemos los registros registros regresados por la base de datos? ¿Cómo mostramos esos registros?</p>
<p>Si leíste el tutorial sobre <a href="http://www.codigometropoli.com/componente-datagrid/">Componente DataGrid</a> y las cuatro entregas del tutorial <a href="http://www.codigometropoli.com/category/air/">Sistema de Clientes en AIR</a> sabrás que podemos recorrer cada uno de los registros obtenidos de la base de datos y almacenarlos en un arreglo por medio del método <em>push</em>; posteriormente ese arreglo es pasado al DataGrid como su proveedor de datos (<em>dataProvider</em>).</p>
<p>Primero hacemos la llamada al método <em>realizarConsulta</em> del servicio <strong>SistemaGastos</strong>:</p>
<pre class="brush: as3;">
responder = new Responder(realizarConsultaResult, errorConsulta);
connection.call(&quot;SistemaGastos.realizarConsulta&quot;, responder, param1, param2, param3...);
</pre>
<p>Definimos el código de nuestra función realizarConsultaResult:</p>
<pre class="brush: as3;">
private function realizarConsultaResult(result:Array):void
{
	if(result != null)
	{
		var totalRegistros:Number = result.length;
		var totales_array:Array = new Array();

		for (var i:int = 0; i &lt; result.length; i++)
		{
	    		...
	       		var divisa_txt:String = result[i].STRNOMBRE;
       			var simbolo_txt:String = result[i].STRSIMBOLO;
	       		...
	    		var cantidad:Number = result[i].NUMCANTIDAD;

		    	if(totales_array.length == 0)
		    		totales_array.push({cantidad:cantidad, divisaID:result[i].INTNUMDIVISA, divisa:divisa_txt, simbolo:result[i].STRSIMBOLO});
	    		else
	    		{
	    			var posicion:Number = regresaPosicionMoneda(totales_array, result[i].INTNUMDIVISA);
		    		if(posicion != -1)
		    		{
	    				var total:Number = totales_array[posicion].cantidad;
	    				total += cantidad;
	    				totales_array[posicion].cantidad = total;
		    		}
		    		else
	    				totales_array.push({cantidad:cantidad, divisaID:result[i].INTNUMDIVISA, divisa:divisa_txt, simbolo:result[i].STRSIMBOLO});
	    			}
data_provider.push({fecha_operacion:DateUtilities.returnReadableDate(result[i].DTMFECHA), concepto:result[i].STRCONCEPTO, cantidad:currencyFormatter.format(result[i].NUMCANTIDAD), cantidad_numero:result[i].NUMCANTIDAD, servicio:servicio_txt, divisa:divisa_txt, operacion:returnTipoOperacion(result[i].INTOPERACION)});
		}

		registros_dg.dataProvider = data_provider;

		info_txt.text = &quot;Total registros: &quot; + totalRegistros + &quot;\n&quot;;
		for(var j:Number = 0; j &lt; totales_array.length; j++)
		{
		 	var simbolo:String = totales_array[j].simbolo;
		 	if(simbolo == &quot;?&quot;)
		 		simbolo = &quot;€&quot;;
		 	currencyFormatter.currencySymbol = simbolo;
		 	info_txt.text += &quot;\n     --&gt; &quot; + totales_array[j].divisa +  &quot; = &quot; + currencyFormatter.format(totales_array[j].cantidad);
		 }
	}
	else
		info_txt.text = &quot;&quot;;

	CursorManager.removeBusyCursor();
}
</pre>
<p>Del código anterior podemos decir que&#8230; primero verificamos que el resultado obtenido por el servicio sea distinto de nulo (es decir, que no esté vacío) ya que si no nos mostraría error. En la variable totalRegistros almacenamos el número de registros obtenidos mediante la propiedad <strong>length</strong> del arreglo. Recorremos el arreglo result por medio de un ciclo <strong>for</strong> y dentro de este ciclo hacemos las operaciones que requerimos con los valores obtenidos. Observa que para acceder a cada una de las columnas de nuestros registros lo hacemos de la forma result[i].STRNOMBRE, result[i].STRSIMBOLO, result[i].INTNUMDIVISA, etc. donde STRNOMBRE, STRSIMBOLO, &#8230; son los nombres de nuestras columnas en la tabla <strong>tbloperacion</strong> de nuestra base de datos. Dentro del código de nuestro ciclo for estamos sumando (ingreso) o restando (si se trata de gasto) las cantidades pertenecientes a un mismo tipo de moneda; y así mostrar la cantidad ganada o gastada por tipo de moneda.</p>
<div align="center"><img src="http://www.codigometropoli.com/images/screens/sistema_gastos_flex1.jpg" alt="Resultado de las operaciones por moneda" /></div>
<p>Dentro del archivo SistemaGastos.php observarás que el código de la función realizarConsulta es largo y está lleno de condicionales. Esto es porque las consultas las podemos realizar de acuerdo a los siguientes criterios:</p>
<div align="center" style="margin-bottom:10px;"><a href="http://www.codigometropoli.com/images/screens/sistema_gastos_flex_consulta.jpg" target="_blank"><br />
<img src="http://www.codigometropoli.com/images/previews/sistema_gastos_flex_consulta.jpg" alt="Forma de consulta de gastos e ingresos" /></a></div>
<p>Hemos llegado al final de este tutorial, no olvidemos revisar el ejemplo y bajar los archivos fuentes.</p>
<div align="center" style="margin-top:10px"><script type="text/javascript"><!--
      google_ad_client = "pub-5808310808246221";
      /* 250x250, Posts */
      google_ad_slot = "8254875600";
      google_ad_width = 250;
      google_ad_height = 250;
// --></script><br />
<script src="http://pagead2.googlesyndication.com/pagead/show_ads.js" type="text/javascript"></script></div>
<div align="center" style="margin-top:40px;margin-bottom:40px;">
<table border="0" cellspacing="0" cellpadding="0" width="180">
<tbody>
<tr>
<td valign="top"><a href="http://www.codigometropoli.com/wp-content/uploads/2008/10/SistemaGastos/Sistema_Gastos.html" target="_blank"><img title="Ver Ejempo" src="http://codigometropoli.com/images/ver_ejemplo.png" alt="Ver Ejemplo" /></a></td>
<td valign="top"><a href="http://www.megaupload.com/?d=DM0QBFMO" target="_blank"><img title="Descargar Archivo" src="../images/descargar.png" alt="Descargar Archivo" /></a></td>
</tr>
</tbody>
</table>
</div>
]]></content:encoded>
			<wfw:commentRss>http://www.codigometropoli.com/sistema-de-gastos-en-flex-con-amfphp-y-mysql/feed/</wfw:commentRss>
		<slash:comments>56</slash:comments>
		</item>
		<item>
		<title>Sistema de Clientes (AIR y SQLite) Parte IV (Consulta a la base de datos)</title>
		<link>http://www.codigometropoli.com/sistema-de-clientes-parte-iv/</link>
		<comments>http://www.codigometropoli.com/sistema-de-clientes-parte-iv/#comments</comments>
		<pubDate>Wed, 10 Sep 2008 05:30:04 +0000</pubDate>
		<dc:creator>Carla Macías</dc:creator>
				<category><![CDATA[AIR]]></category>
		<category><![CDATA[Proyectos]]></category>
		<category><![CDATA[Base de datos]]></category>
		<category><![CDATA[Flex]]></category>
		<category><![CDATA[Proyecto]]></category>
		<category><![CDATA[Sistema]]></category>

		<guid isPermaLink="false">http://www.codigometropoli.com/?p=350</guid>
		<description><![CDATA[Esta es la cuarta y última parte del proyecto &#8220;Sistema de Clientes&#8221; desarrollado en AIR con SQLite como administrador de base de datos. En la entrada anterior vimos cómo modificar y eliminar registros en la base de datos (clientesDB.sqlite) desde nuestra aplicación en AIR. En esta ocasión veremos cómo realizar consultas de los registros en [...]]]></description>
			<content:encoded><![CDATA[<p><img class="alignright" style="float: right;" src="http://codigometropoli.com/images/air.png" alt="Adobe AIR" width="93" height="93" />Esta es la cuarta y última parte del proyecto &#8220;Sistema de Clientes&#8221; desarrollado en AIR con SQLite como administrador de base de datos. En la <a href="http://www.codigometropoli.com/sistema-de-clientes-parte-iii/" target="_blank">entrada</a> anterior vimos cómo modificar y eliminar registros en la base de datos (<em>clientesDB.sqlite</em>) desde nuestra aplicación en AIR.</p>
<p><span id="more-350"></span></p>
<p>En esta ocasión veremos cómo realizar consultas de los registros en la base de datos; para esto crearemos una forma en la cual el usuario puede introducir el nombre, teléfono o correo del cliente que está buscando. Los resultados de esta consulta los escribiremos en un archivo HTML y lo mostraremos dentro del componente <strong>HTML </strong>(aprovechando el <a href="http://www.codigometropoli.com/crear-archivo-en-air-con-flex-builder-3/" target="_blank">post</a> que publiqué hace ya tiempo sobre cómo crear un archivo en AIR).</p>
<p><span style="color: #ff0000;"><strong>Parte 4: Consulta a la base de datos en SQLite con AIR</strong></span></p>
<p>Recuerda que para mantener organizado el código de nuestro proyecto y para evitar que se pierdan con toda la información aquí mostrada, dividí el código del proyecto en archivos .as. Estos archivos estarán almacenados en la carpeta actionscript. La estructura de nuestro proyecto será la siguiente:</p>
<div align="center">
<div class="wp-caption aligncenter" style="width: 255px"><img title="Imagen 1: Estructura de la aplicación" src="http://www.codigometropoli.com/wp-content/uploads/2008/08/proy1image1.jpg" alt="Imagen 1: Estructura de la aplicación" width="245" height="373" />
<p class="wp-caption-text">Imagen 1: Estructura de la aplicación</p>
</div>
</div>
<p>Todas las interfaces de este proyecto están incluidas en la carpeta <em>componentes</em>. La interfaz que en esta ocasión veremos es la del archivo <em>ConsultaClientes.mxml</em>. Esta interfaz funciona de la siguiente manera:</p>
<div align="center">
<div class="wp-caption aligncenter" style="width: 391px"><a href="http://www.codigometropoli.com/images/screens/proy1image7.jpg" target="_blank"><img alt="Imagen 2: Interfaz del usuario" src="http://www.codigometropoli.com/images/previews/proy1image7.jpg" title="Imagen 2: Interfaz del usuario" width="381" height="295" /></a><p class="wp-caption-text">Imagen 2: Interfaz del usuario</p></div>
</div>
<p>Al seleccionar la opción &#8220;Consultar…&#8221; del menú, se mostrará una forma con tres campos de texto, en donde el usuario podrá introducir el nombre, teléfono y correo del cliente que está buscando. Además, en la forma tendremos el botón de <em>Mostrar</em>el cual ejecutará la búsqueda. Los resultados serán mostrados dentro del rectángulo que ves en la parte de abajo de la imagen anterior.</p>
<p>Una vez que el usuario ejecute al búsqueda, si no se encontraron registros que coincidan con los datos buscados, el sistema mostrará dentro del archivo HTML la leyenda &#8220;<em>No se encontraron resultados</em>&#8220;. En caso contrario, el sistema mostrará los resultados de forma similar a la mostrada a continuación:</p>
<div align="center">
<div class="wp-caption aligncenter" style="width: 389px"><a href="http://www.codigometropoli.com/images/screens/proy1image8.jpg" target="_blank"><img alt="Imagen 2: Interfaz del usuario" src="http://www.codigometropoli.com/images/previews/proy1image8.jpg" title="Imagen 3: Resultado de la consulta" width="379" height="267" /></a><p class="wp-caption-text">Imagen 2: Interfaz del usuario</p></div>
</div>
<p>Dicho lo anterior, comenzaremos mostrando la estructura y el código del archivo <em>ConsultaClientes.mxml</em>:</p>
<ul>
<li>El <strong>ID</strong> del <strong>TextInput</strong> Nombre es <em>nombre_txt</em></li>
<li>El <strong>ID</strong> del <strong>TextInput</strong> Correo es <em>correo_txt</em></li>
<li>El <strong>ID</strong> del <strong>TextInput</strong> Teléfono es <em>teléfono_txt</em></li>
<li>El <strong>ID</strong> del componente <strong>HTML</strong> es <em>HTMLLoader</em></li>
</ul>
<p>El código de este  archivo  es el siguiente:</p>
<pre class="brush: as3;">
&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
&lt;mx:Canvas show=&quot;abreConexion();&quot; xmlns:mx=&quot;http://www.adobe.com/2006/mxml&quot; width=&quot;100%&quot; height=&quot;100%&quot; backgroundColor=&quot;#FFFFFF&quot;&gt;
	&lt;mx:Script source=&quot;../actionscript/ConsultarCliente.as&quot;/&gt;
	&lt;mx:Label y=&quot;13&quot; text=&quot;Consulta de Clientes&quot; right=&quot;75&quot; left=&quot;55&quot; textAlign=&quot;center&quot; fontWeight=&quot;bold&quot; fontSize=&quot;14&quot; fontFamily=&quot;Verdana&quot; color=&quot;#F64507&quot;/&gt;
	&lt;mx:Label y=&quot;61&quot; text=&quot;Mostrar clientes por:&quot; textAlign=&quot;left&quot; fontWeight=&quot;normal&quot; fontSize=&quot;12&quot; fontFamily=&quot;Verdana&quot; color=&quot;#000000&quot; width=&quot;151&quot; x=&quot;31&quot; textDecoration=&quot;underline&quot;/&gt;
	&lt;mx:Label y=&quot;89&quot; text=&quot;Nombre:&quot; textAlign=&quot;left&quot; fontWeight=&quot;normal&quot; fontSize=&quot;12&quot; fontFamily=&quot;Verdana&quot; color=&quot;#000000&quot; width=&quot;83&quot; x=&quot;62&quot;/&gt;
	&lt;mx:Label y=&quot;119&quot; text=&quot;Correo:&quot; textAlign=&quot;left&quot; fontWeight=&quot;normal&quot; fontSize=&quot;12&quot; fontFamily=&quot;Verdana&quot; color=&quot;#000000&quot; width=&quot;65&quot; x=&quot;62&quot;/&gt;
	&lt;mx:Label y=&quot;89&quot; text=&quot;Teléfono:&quot; textAlign=&quot;left&quot; fontWeight=&quot;normal&quot; fontSize=&quot;12&quot; fontFamily=&quot;Verdana&quot; color=&quot;#000000&quot; width=&quot;74&quot; x=&quot;285&quot;/&gt;
	&lt;mx:Button x=&quot;415&quot; y=&quot;119&quot; label=&quot;Mostrar&quot; click=&quot;generaConsulta();&quot;/&gt;
	&lt;mx:HTML focusEnabled=&quot;false&quot; id=&quot;HTMLLoader&quot; borderStyle=&quot;solid&quot; left=&quot;31&quot; top=&quot;171&quot; right=&quot;31&quot; bottom=&quot;21&quot;/&gt;
	&lt;mx:TextInput y=&quot;89&quot; width=&quot;130&quot; height=&quot;21&quot; id=&quot;nombre_txt&quot; fontSize=&quot;10&quot; fontFamily=&quot;Verdana&quot; x=&quot;123&quot;/&gt;
	&lt;mx:TextInput y=&quot;89&quot; width=&quot;130&quot; height=&quot;21&quot; id=&quot;telefono_txt&quot; fontSize=&quot;10&quot; fontFamily=&quot;Verdana&quot; x=&quot;355&quot;/&gt;
	&lt;mx:TextInput y=&quot;119&quot; width=&quot;130&quot; height=&quot;21&quot; id=&quot;correo_txt&quot; fontSize=&quot;10&quot; fontFamily=&quot;Verdana&quot; x=&quot;123&quot;/&gt;
&lt;/mx:Canvas&gt;
</pre>
<p>Observa en el código anterior que el tag principal de este archivo es <strong>&lt;mx:Canvas&gt;</strong> y no <strong>&lt;mx:WindowedApplication&gt;</strong>, esto es porque todas las interfaces que están dentro del directorio componentes las desplegaremos dentro de la aplicación principal (<em>Sistema_Clientes.mxml</em>); a la propiedad <strong>show</strong> del <strong>Canvas</strong> le estamos especificando que llame a la función  <em>abreConexion() </em>una vez que se haya terminado de mostrar el componente. También observa cómo estamos incluyendo el código de <em>ConsultarCliente.as</em>:</p>
<pre class="brush: as3;">
&lt;mx:Script source=&quot;../actionscript/ConsultarCliente.as&quot;/&gt;
</pre>
<p>Dentro del código del botón <em>Mostrar</em> hacemos la llamada a la función <em>generaConsulta</em> una vez que el usuario haya hecho click en dicho botón. El código de esta función (<em>generaConsulta</em>) y de la función principal (<em>abreConexion</em>) se encuentra dentro del archivo ConsultarCliente.as:</p>
<pre class="brush: as3;">
/* Importamos todas las librerías y clases que necesitamos. La clase HTMLTags la hice para establecer el código de cada elemento del archivo HTML, así como los estilos que usa dicho archivo; esta clase la veremos más adelante. */
import clases.HTMLTags;
	import flash.data.SQLConnection;
	import flash.events.SQLErrorEvent;
	import flash.events.SQLEvent;
	import flash.filesystem.File;
	import flash.html.HTMLLoader;
	import mx.controls.Alert;

/* Es importante establecer el tipo de codficación (encodeType) para que, al momento de escribir y generar el archivo, se muestren los acentos correctamente.  */
	private var _encodeType:String = &quot;iso-8859-1&quot;;
	private var conexion:SQLConnection;
	private var database:File;
	private var stream:FileStream = new FileStream(); /* Declaramos una variable de tipo FileStream para poder crear y escribir en el archivo */
	private var htmlElements:HTMLTags = new HTMLTags();/* Este es un objeto de nuestra clase HTMLTags */
	private var queryStatement:SQLStatement = new SQLStatement();
public function abreConexion():void {
	    database = new File(File.applicationStorageDirectory.nativePath + &quot;\database\clientesDB.sqlite&quot;);
	    conexion = new SQLConnection();
	    conexion.addEventListener(SQLEvent.OPEN, dbAbrirConexion);
	    conexion.addEventListener(SQLErrorEvent.ERROR, dbErrorConexion);
	    conexion.open(database);
	}

	private function dbAbrirConexion(event:SQLEvent):void {

	}

	private function dbErrorConexion():void {
		Alert.show(&quot;No se pudo conectar a la base de datos&quot;);
	}
</pre>
<p>Después de haber importado las librerías necesarias y de haber declarado nuestras variables, escribimos el código de la función <em>abreConexion</em>. Esta función la hemos estado utilizando en las entradas anteriores, por lo que su código no debería causarte ruido.</p>
<p>Antes de ver el código de la función <em>generaConsulta</em>, mostraré el código de la clase HTMLTags:</p>
<pre class="brush: as3;">
package clases
{
	public class HTMLTags
	{
		public function HTMLTags()
		{
		}

		public function getEndTags():String {
			var _texto:String = '&lt;/body&gt;\n&lt;/html&gt;\n';
			return _texto;
		}

		public function getRulerTag():String {
			var _texto:String = '&lt;hr class=&quot;Ruler&quot; /&gt;\n';
			return _texto;
		}

		public function getFirstTags():String {
			var _texto:String = '&lt;!DOCTYPE html PUBLIC &quot;-//W3C//DTD XHTML 1.0 Transitional//EN&quot; &quot;http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd&quot;&gt;\n' +
			'&lt;html xmlns=&quot;http://www.w3.org/1999/xhtml&quot;&gt;\n' +
			'&lt;head&gt;\n' +
			'&lt;meta http-equiv=&quot;Content-Type&quot; content=&quot;text/html; charset=iso-8859-2&quot; /&gt;\n' +
			'&lt;title&gt;Consulta: Tarjetas&lt;/title&gt;\n' +
			'&lt;style&gt;\n' +
			'body {\n' +
			'	font:Arial, Helvetica, sans-serif;\n' +
			'	font-family:Arial, Helvetica, sans-serif;\n' +
			'	font-size:12px;\n' +
			'	margin-left:30px;\n' +
			'}\n' +
			'hr.Ruler {\n' +
			'	margin-left:-20px !important;\n' +
			'	color:#003366;\n' +
			'	border:1px solid #003366;\n' +
			'	background-color:#003366;\n' +
			'	width:800px;\n' +
			'}\n' +
			'.Estilo3 {\n' +
			'	color: #993300;\n' +
			'	font-weight: bold;\n' +
			'	font-size: 14px;\n' +
			'}\n' +
			'.Estilo4 {font-size: 12px; color: #666666;}\n' +
			'.Tabla_Datos td {\n' +
			'	height:25px;\n' +
			'}\n' +
			'&lt;/style&gt;\n' +
			'&lt;/head&gt;\n' +
			'&lt;body&gt;\n';
			return _texto;
		}

		public function getTitleTags(name:String):String {
			var _texto:String = '&lt;br /&gt;&lt;span class=&quot;Estilo3&quot;&gt;' + name + '&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;\n';
			return _texto;
		}

		public function getTable1Tags(nombre:String, direccion:String):String {
			var _texto:String = '&lt;table class=&quot;Tabla_Datos&quot; width=&quot;700&quot; border=&quot;0&quot; cellspacing=&quot;0&quot; cellpadding=&quot;0&quot;&gt;\n' +
		'  &lt;tr&gt;\n' +
		'    &lt;td&gt;&lt;strong&gt;Nombre:&lt;/strong&gt;&lt;/td&gt;\n' +
		'    &lt;td&gt;' + nombre + '&lt;/td&gt;\n' +
		'    &lt;td&gt;&lt;strong&gt;Dirección:&lt;/strong&gt;&lt;/td&gt;\n' +
		'    &lt;td&gt;' + direccion + '&lt;/td&gt;\n' +
		'  &lt;/tr&gt;\n';
			return _texto;
		}

		public function getTable2Tags(telefono:String, correo:String):String {
			var _texto:String = '' +
		'  &lt;tr&gt;\n' +
		'    &lt;td&gt;&lt;strong&gt;Teléfono:&lt;/strong&gt;&lt;/td&gt;\n' +
		'    &lt;td&gt;' + telefono + '&lt;/td&gt;\n' +
		'    &lt;td&gt;&lt;strong&gt;Correo:&lt;/strong&gt;&lt;/td&gt;\n' +
		'    &lt;td&gt;' + correo + '&lt;/td&gt;\n' +
		'  &lt;/tr&gt;\n' +
		'&lt;/table&gt;\n';
			return _texto;
		}
	}
}
</pre>
<p>Como pudiste observar en el código anterior, esta clase lo único que hace es regresarnos los tags del documento HTML que vamos a generar. Por ejemplo, la función <em>getFirstTags</em> nos regresa los primeros elementos que debe llevar el archivo HTML (los tags &lt;html&gt;, &lt;head&gt;, &lt;meta&gt; y los estilos que usaremos &lt;style&gt;). La función <em>getTitleTags</em> la mandaremos a llamar cada vez que recorramos un nuevo registro, le pasaremos como parámetro un texto de tipo &#8220;Cliente N&#8221; donde N es el valor de un contador que pondremos en el código (Cliente #1, Cliente #2, etc.) y nos regresará un texto con los tags y estilo que debe llevar. A la función <em>getTable1Tags</em> le estamos pasando como parámetro el nombre y la dirección del cliente, y ésta a su vez nos está regresando la información en forma de tabla con el código en HTML. Lo mismo sucede con la función <em>getTable2Tags</em>. La función <em>getRulerTag</em> nos regresa el tag &lt;hr&gt; para mostrar una línea horizontal. Por último, la función <em>getEndTags</em> nos regresa un texto con los tags que nos faltaban por cerrar (&lt;/body&gt; y &lt;/html&gt;).</p>
<p>Ahora veremos el código de generaConsulta. Presta atención en los comentarios que se encuentran dentro del código:</p>
<pre class="brush: as3;">
private function generaConsulta():void {
		var prep:String = &quot; WHERE &quot;;

		queryStatement.clearParameters();
		queryStatement.sqlConnection = conexion;

		var genericQuery:String = &quot;SELECT * FROM cliente &quot;; /* Seleccionamos todas las columnas del registro */

		if(nombre_txt.text != &quot;&quot;) { /* Si el usuario sí escribió algo en el campo de texto nombre_txt */
			genericQuery += prep + &quot; nombre LIKE '%&quot; + nombre_txt.text + &quot;%'&quot;; /* Adjuntamos al query el valor del campo de texto nombre */
			prep = &quot; AND &quot;;
		}
		if(correo_txt.text != &quot;&quot;) { /* Si el usuario sí escribió algo en el campo de texto correo_txt */
			genericQuery += prep + &quot; email LIKE '%&quot; + correo_txt.text + &quot;%'&quot;; /* Adjuntamos al query el valor del campo de texto correo */
			prep = &quot; AND &quot;;
		}
		if(telefono_txt.text != &quot;&quot;) { /* Si el usuario sí escribió algo en el campo de texto telefono_txt */
			genericQuery += prep + &quot; telefono LIKE '%&quot; + telefono_txt.text + &quot;%'&quot;; /* Adjuntamos al query el valor del campo de texto telefono */
			prep = &quot; AND &quot;;
		}

		genericQuery += &quot; ORDER BY nombre asc&quot;; /* Le especificamos al query que los resultados los ordene de manera ascendente de acuerdo al nombre del cliente */		

		queryStatement.text = genericQuery; // Asignamos la variable del query al SQLStatement

		try {
			queryStatement.execute(); // Ejecutamos la consulta

			/* Este será el archivo HTML que estamos creando. Su nombre es ConsultaCliente.html y se encontrará dentro de la carpeta HTML */
			var htmlFile:File = new File(File.applicationStorageDirectory.nativePath + &quot;/HTML/ConsultaCliente.html&quot;);

			if(stream != null) {
				stream.close(); /* Cerramos el stream si es que existe */
			}
			stream = new FileStream();
			stream.open(htmlFile, FileMode.WRITE); /* Abrimos el stream en modo de escritura */
			stream.addEventListener(IOErrorEvent.IO_ERROR, writeIOErrorHandler); /* Establecemos un listener para detectar el evento */

			var result:SQLResult = queryStatement.getResult(); /* Obtenemos los resultados regresados por la consulta */

			if(result.data != null) { // Si existen resultados...
				var numResults:int = result.data.length; // Determinamos el total de resultados regresados

				stream.writeUTFBytes(htmlElements.getFirstTags()); /* Escribimos en el archivo el texto regresado por la clase HTMLTags en su función getFirstTags */

		    	for (var i:int = 0; i &lt; numResults; i++) // Hacemos un ciclo para recorrer todos los registros obtenidos
			    {
			    	var row:Object = result.data[i];
			    	row.nombre;			    	

		    	/* Esta parte entraría a un ciclo */
					stream.writeMultiByte(htmlElements.getTitleTags(&quot;Cliente #&quot; + (i + 1)), _encodeType);
					stream.writeMultiByte(htmlElements.getTable1Tags(row.nombre, row.direccion), _encodeType);
					stream.writeMultiByte(htmlElements.getTable2Tags(row.telefono, row.email), _encodeType);
					stream.writeUTFBytes(htmlElements.getRulerTag());
				/* Esta parte entraría a un ciclo */
			    }
			    stream.writeUTFBytes(htmlElements.getEndTags());
			}
		    else {
		    	stream.writeUTFBytes(&quot;No se encontraron resultados&quot;);
		    }
		    stream.close();
		}
		catch(error:SQLError) {
			trace(&quot;Error: &quot; + error.toString());
		}

		/* Si todo salió bien, ahora podremos mostrar el archivo html en nuestro HTMLLoader */
		HTMLLoader.location = File.applicationStorageDirectory.nativePath + &quot;/HTML/ConsultaCliente.html&quot;;
	}
</pre>
<p>Observa que al final estamos especificando al control <strong>HTML</strong> (cuyo <strong>ID</strong> es <em>HTMLLoader</em>) el archivo HTML que debe mostrar (ConsultaCliente.html dentro de la carpeta HTML).</p>
<p>Hemos llegado al final de esta cuarta parte y de todas las entregas, no olvides bajar los archivos que se encuentran más abajo.</p>
<div align="center" style="margin-top:0px"><script type="text/javascript"><!--
      google_ad_client = "pub-5808310808246221";
      /* 250x250, Posts */
      google_ad_slot = "8254875600";
      google_ad_width = 250;
      google_ad_height = 250;
// --></script><br />
<script src="http://pagead2.googlesyndication.com/pagead/show_ads.js" type="text/javascript"></script></div>
<div style="margin-top:30px; margin-bottom:20px;" align="center">
<table border="0" cellspacing="0" cellpadding="0" width="180">
<tbody>
<tr>
<td valign="top"><a href="http://www.megaupload.com/?d=277H67ZZ" target="_blank"><img src="../images/descargar.png" alt="Descargar Archivo" /></a></td>
</tr>
</tbody>
</table>
</div>
<div style="margin-top:40px; margin-bottom:30px;">
<p><strong>Enlaces recomendados:</strong></p>
<p>» <a href="http://livedocs.adobe.com/flex/3/html/help.html?content=SQL_01.html" target="_blank">Working with local SQL databases</a><br />
» <a href="http://livedocs.adobe.com/flex/3/langref/index.html" target="_blank">Adobe® Flex® 3 Language Reference</a></div>
]]></content:encoded>
			<wfw:commentRss>http://www.codigometropoli.com/sistema-de-clientes-parte-iv/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Sistema de Clientes (AIR y SQLite) Parte III (Modificar y Eliminar Registros)</title>
		<link>http://www.codigometropoli.com/sistema-de-clientes-parte-iii/</link>
		<comments>http://www.codigometropoli.com/sistema-de-clientes-parte-iii/#comments</comments>
		<pubDate>Mon, 08 Sep 2008 04:15:49 +0000</pubDate>
		<dc:creator>Carla Macías</dc:creator>
				<category><![CDATA[AIR]]></category>
		<category><![CDATA[Proyectos]]></category>
		<category><![CDATA[Base de datos]]></category>
		<category><![CDATA[Flex]]></category>
		<category><![CDATA[Proyecto]]></category>
		<category><![CDATA[Sistema]]></category>

		<guid isPermaLink="false">http://www.codigometropoli.com/?p=334</guid>
		<description><![CDATA[Esta es la tercera parte del proyecto &#8220;Sistema de Clientes&#8221; desarrollado en AIR con SQLite como administrador de base de datos. En la entrada anterior vimos cómo insertar registros en la base de datos (clientesDB.sqlite) desde nuestra aplicación en AIR. En esta ocasión veremos cómo editar y eliminar registros de la base de datos; para [...]]]></description>
			<content:encoded><![CDATA[<p><img class="alignright" style="float: right;" src="http://codigometropoli.com/images/air.png" alt="Adobe AIR" width="93" height="93" />Esta es la tercera parte del proyecto &#8220;Sistema de Clientes&#8221; desarrollado en AIR con SQLite como administrador de base de datos. En la <a href="http://www.codigometropoli.com/sistema-de-clientes-parte-ii/" target="_blank">entrada</a> anterior vimos cómo insertar registros en la base de datos (<em>clientesDB.sqlite</em>) desde nuestra aplicación en AIR.<br />
En esta ocasión veremos cómo editar y eliminar registros de la base de datos; para esto mostraremos dentro de un DataGrid todos los registros que tenemos en nuestra base de datos; en este DataGrid usaremos <strong>itemRenderer(s)</strong> para llenar con botones dos columnas, uno de los botones será para editar el registro seleccionado y el otro para eliminarlo.</p>
<p><span id="more-334"></span><span style="color: #ff0000;"><strong>Parte 3: Modificar y eliminar registros en SQLite con AIR</strong></span></p>
<p>Recuerda que para mantener organizado el código de nuestro proyecto y para evitar que se pierdan con toda la información aquí mostrada, dividí el código del proyecto en archivos .as. Estos archivos estarán almacenados en la carpeta actionscript. La estructura de nuestro proyecto será la siguiente:</p>
<div align="center">
<div class="wp-caption aligncenter" style="width: 255px"><img title="Imagen 1: Estructura de la aplicación" src="http://www.codigometropoli.com/wp-content/uploads/2008/08/proy1image1.jpg" alt="Imagen 1: Estructura de la aplicación" width="245" height="373" /><p class="wp-caption-text">Imagen 1: Estructura de la aplicación</p></div>
</div>
<p>Todas las interfaces de este proyecto están incluidas en la carpeta componentes. La interfaz que en esta ocasión veremos es la del archivo <em>EditarBorrarCliente.mxml</em>. Esta interfaz funciona de la siguiente manera:</p>
<div align="center">
<div class="wp-caption aligncenter" style="width: 552px"><a href="http://www.codigometropoli.com/images/screens/proy1image4.jpg" target="_blank"><img title="Imagen 2: Interfaz del usuario" src="http://www.codigometropoli.com/images/previews/proy1image4.jpg" alt="Imagen 2: Interfaz del usuario" width="542" height="255" /></a><p class="wp-caption-text">Imagen 2: Interfaz del usuario</p></div>
</div>
<p>Al seleccionar la opción &#8220;Editar/Eliminar…&#8221; del menú, se mostrará un DataGrid con todos los registros que tenemos dados de alta en nuestra base. En este ejemplo solamente tengo dos registros. Si el usuario hace click al botón de <strong>Modificar</strong> del primer registro, se mostrará lo siguiente:</p>
<div align="center">
<div class="wp-caption aligncenter" style="width: 552px"><a href="http://www.codigometropoli.com/images/screens/proy1image5.jpg" target="_blank"><img title="Imagen 3: Opción Modificar Cliente" src="http://www.codigometropoli.com/images/screens/proy1image5.jpg" alt="Imagen 3: Opción Modificar Cliente" width="542" height="511" /></a><p class="wp-caption-text">Imagen 3: Opción Modificar Cliente</p></div>
</div>
<p>…Un Canvas con los datos de nuestro registro. Si el usuario lo desea, podrá modificar o actualizar los datos de este registro. Por el contrario, si el usuario le da click al botón de <strong>Eliminar</strong> del primer registro, se mostrará un mensaje de alerta pidiéndole que confirme si desea o no borrar el registro.</p>
<div align="center">
<div class="wp-caption aligncenter" style="width: 551px"><a href="http://www.codigometropoli.com/images/screens/proy1image6.jpg" target="_blank"><img title="Imagen 4: Mensaje de confirmación" src="http://www.codigometropoli.com/images/previews/proy1image6.jpg" alt="Imagen 4: Mensaje de confirmación" width="541" height="254" /></a><p class="wp-caption-text">Imagen 4: Mensaje de confirmación</p></div>
</div>
<p>Explicado lo anterior, comenzaremos mostrando la estructura y el código del archivo EditarBorrarCliente.mxml:</p>
<ul>
<li> El <strong>ID</strong> del <strong>DataGrid </strong>donde mostraremos los registros es <em>clientes_dg</em></li>
<li>El <strong>ID </strong>de nuestro <strong>Canvas </strong>en donde mostraremos la información del registro que el usuario puede modificar es <em>Modificar_Cliente</em>
<ul>
<li>El botón de <em>Cambiar</em> que se encuentra dentro del Canvas tiene de <strong>ID </strong><em>guardarBtn</em></li>
<li>El botón con una X tiene de <strong>ID </strong><em>cerrarBtn</em></li>
<li>Los <strong>ID</strong>s de cada una de las áreas de texto son:
<ul>
<li>nombre_txt, direccion_txt (TextArea), telefono_txt, correo_txt</li>
<li>Además, tenemos tres etiquetas cuyo texto es <strong>(*)</strong> y con los cuales le indicaremos al usuario qué dato le faltó por llenar. Estas etiquetas tienen de <strong>ID</strong>: <em>msj1</em>, <em>msj2</em>, <em>msj3</em> y <em>msj4</em>.</li>
</ul>
</li>
</ul>
</li>
</ul>
<p>El código de este  archivo  es el siguiente:</p>
<pre class="brush: as3;">
&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
&lt;mx:Canvas show=&quot;abreConexion();&quot; xmlns:mx=&quot;http://www.adobe.com/2006/mxml&quot; width=&quot;100%&quot; height=&quot;100%&quot; backgroundColor=&quot;#FFFFFF&quot;&gt;
	&lt;mx:Script source=&quot;../actionscript/EditarBorrarCliente.as&quot;/&gt;
	&lt;mx:Label y=&quot;13&quot; text=&quot;Lista de Clientes&quot; right=&quot;75&quot; left=&quot;55&quot; textAlign=&quot;center&quot; fontWeight=&quot;bold&quot; fontSize=&quot;14&quot; fontFamily=&quot;Verdana&quot; color=&quot;#F64507&quot;/&gt;
	&lt;mx:DataGrid y=&quot;57&quot; width=&quot;600&quot; height=&quot;223&quot; horizontalCenter=&quot;-14&quot; id=&quot;clientes_dg&quot;&gt;
		&lt;mx:columns&gt;
			&lt;mx:DataGridColumn width=&quot;150&quot; textAlign=&quot;left&quot; headerText=&quot;Nombre&quot; dataField=&quot;nombre&quot;/&gt;
			&lt;mx:DataGridColumn width=&quot;120&quot; textAlign=&quot;left&quot; headerText=&quot;Teléfono&quot; dataField=&quot;telefono&quot;/&gt;
			&lt;mx:DataGridColumn width=&quot;165&quot; textAlign=&quot;left&quot; headerText=&quot;Correo&quot; dataField=&quot;correo&quot;/&gt;
			&lt;mx:DataGridColumn sortable=&quot;false&quot; width=&quot;85&quot; textAlign=&quot;center&quot; headerText=&quot;Modificar&quot; dataField=&quot;modificar&quot;&gt;
				&lt;mx:itemRenderer&gt;
				&lt;mx:Component&gt;
					&lt;mx:HBox horizontalAlign=&quot;center&quot;&gt;
						&lt;mx:Button id=&quot;editarBtn&quot; click=&quot;outerDocument.editarCliente(data.id_cliente, data.nombre, data.direccion, data.telefono, data.correo)&quot; label=&quot;&quot; height=&quot;20&quot; width=&quot;30&quot; icon=&quot;@Embed(source='../images/edit.png')&quot;/&gt;
					&lt;/mx:HBox&gt;
				&lt;/mx:Component&gt;
				&lt;/mx:itemRenderer&gt;
			&lt;/mx:DataGridColumn&gt;
			&lt;mx:DataGridColumn sortable=&quot;false&quot; width=&quot;80&quot; textAlign=&quot;center&quot; headerText=&quot;Eliminar&quot; dataField=&quot;eliminar&quot;&gt;
				&lt;mx:itemRenderer&gt;
				&lt;mx:Component&gt;
					&lt;mx:HBox horizontalAlign=&quot;center&quot;&gt;
						&lt;mx:Button id=&quot;borrarBtn&quot; click=&quot;outerDocument.borrarCliente(data.id_cliente)&quot; label=&quot;&quot; height=&quot;20&quot; width=&quot;30&quot; icon=&quot;@Embed(source='../images/remove.png')&quot;/&gt;
					&lt;/mx:HBox&gt;
				&lt;/mx:Component&gt;
				&lt;/mx:itemRenderer&gt;
			&lt;/mx:DataGridColumn&gt;
		&lt;/mx:columns&gt;
	&lt;/mx:DataGrid&gt;
	&lt;mx:Canvas id=&quot;Modificar_Cliente&quot; visible=&quot;true&quot; y=&quot;324&quot; width=&quot;378&quot; height=&quot;255&quot; horizontalCenter=&quot;-15&quot; borderColor=&quot;#ADADAD&quot; backgroundAlpha=&quot;0.0&quot; borderStyle=&quot;solid&quot;&gt;
		&lt;mx:Button id=&quot;guardarBtn&quot; click=&quot;validaForma();&quot; y=&quot;221&quot; label=&quot;Cambiar&quot; width=&quot;100&quot; x=&quot;220&quot;/&gt;
		&lt;mx:Label y=&quot;10&quot; text=&quot;Modificar Cliente:&quot; textAlign=&quot;left&quot; fontWeight=&quot;bold&quot; fontSize=&quot;11&quot; fontFamily=&quot;Verdana&quot; color=&quot;#31384B&quot; width=&quot;213&quot; x=&quot;10&quot; textDecoration=&quot;underline&quot;/&gt;
		&lt;mx:Button id=&quot;cerrarBtn&quot; y=&quot;1&quot; label=&quot;X&quot; width=&quot;32&quot; x=&quot;343.3&quot; click=&quot;Modificar_Cliente.visible = false; reseteaForma();&quot; cornerRadius=&quot;0&quot;/&gt;
		&lt;mx:Text visible=&quot;false&quot; x=&quot;10&quot; y=&quot;86&quot; text=&quot;Por favor introduzca la divisa&quot; fontWeight=&quot;bold&quot; color=&quot;#B80808&quot; fontFamily=&quot;Verdana&quot; fontSize=&quot;10&quot; width=&quot;184&quot; height=&quot;33&quot; id=&quot;msj_nombre&quot;/&gt;
		&lt;mx:TextInput y=&quot;50&quot; width=&quot;212&quot; height=&quot;21&quot; id=&quot;nombre_txt&quot; fontSize=&quot;10&quot; fontFamily=&quot;Verdana&quot; x=&quot;108&quot;/&gt;
		&lt;mx:TextArea y=&quot;81&quot; width=&quot;212&quot; height=&quot;69&quot; id=&quot;direccion_txt&quot; x=&quot;108&quot;/&gt;
		&lt;mx:TextInput y=&quot;161&quot; width=&quot;212&quot; height=&quot;21&quot; id=&quot;telefono_txt&quot; fontSize=&quot;10&quot; fontFamily=&quot;Verdana&quot; x=&quot;108&quot;/&gt;
		&lt;mx:TextInput y=&quot;190&quot; width=&quot;212&quot; height=&quot;21&quot; id=&quot;correo_txt&quot; fontSize=&quot;10&quot; fontFamily=&quot;Verdana&quot; x=&quot;108&quot;/&gt;
		&lt;mx:Label y=&quot;50&quot; text=&quot;Nombre:&quot; fontSize=&quot;12&quot; fontFamily=&quot;Verdana&quot; fontWeight=&quot;normal&quot; color=&quot;#000000&quot; width=&quot;80&quot; textAlign=&quot;right&quot; x=&quot;10&quot;/&gt;
		&lt;mx:Label y=&quot;86&quot; text=&quot;Dirección:&quot; fontSize=&quot;12&quot; fontFamily=&quot;Verdana&quot; fontWeight=&quot;normal&quot; color=&quot;#000000&quot; width=&quot;80&quot; textAlign=&quot;right&quot; x=&quot;10&quot;/&gt;
		&lt;mx:Label y=&quot;161&quot; text=&quot;Teléfono:&quot; fontSize=&quot;12&quot; fontFamily=&quot;Verdana&quot; fontWeight=&quot;normal&quot; color=&quot;#000000&quot; width=&quot;80&quot; textAlign=&quot;right&quot; x=&quot;10&quot;/&gt;
		&lt;mx:Label y=&quot;190&quot; text=&quot;Correo:&quot; fontSize=&quot;12&quot; fontFamily=&quot;Verdana&quot; fontWeight=&quot;normal&quot; color=&quot;#000000&quot; width=&quot;80&quot; textAlign=&quot;right&quot; x=&quot;10&quot;/&gt;
		&lt;mx:Label y=&quot;50&quot; text=&quot;(*)&quot; fontSize=&quot;10&quot; fontFamily=&quot;Verdana&quot; fontWeight=&quot;bold&quot; color=&quot;#B80808&quot; width=&quot;27&quot; textAlign=&quot;left&quot; id=&quot;msj1&quot; visible=&quot;false&quot; horizontalCenter=&quot;153&quot;/&gt;
		&lt;mx:Label y=&quot;82&quot; text=&quot;(*)&quot; fontSize=&quot;10&quot; fontFamily=&quot;Verdana&quot; fontWeight=&quot;bold&quot; color=&quot;#B80808&quot; width=&quot;27&quot; textAlign=&quot;left&quot; id=&quot;msj2&quot; visible=&quot;false&quot; horizontalCenter=&quot;153&quot;/&gt;
		&lt;mx:Label y=&quot;161&quot; text=&quot;(*)&quot; fontSize=&quot;10&quot; fontFamily=&quot;Verdana&quot; fontWeight=&quot;bold&quot; color=&quot;#B80808&quot; width=&quot;27&quot; textAlign=&quot;left&quot; id=&quot;msj3&quot; visible=&quot;false&quot; horizontalCenter=&quot;153&quot;/&gt;
		&lt;mx:Label y=&quot;190&quot; text=&quot;(*)&quot; fontSize=&quot;10&quot; fontFamily=&quot;Verdana&quot; fontWeight=&quot;bold&quot; color=&quot;#B80808&quot; width=&quot;27&quot; textAlign=&quot;left&quot; id=&quot;msj4&quot; visible=&quot;false&quot; horizontalCenter=&quot;153&quot;/&gt;
	&lt;/mx:Canvas&gt;
&lt;/mx:Canvas&gt;
</pre>
<p>Observa en el código anterior que el tag principal de este archivo es <strong>&lt;mx:Canvas&gt; </strong>y no <strong>&lt;mx:WindowedApplication&gt;</strong>, esto es porque todas las interfaces que están dentro del directorio componentes las desplegaremos dentro de la aplicación principal (<em>Sistema_Clientes.mxml</em>); a la propiedad <strong>show </strong>del <strong>Canvas </strong>le estamos especificando que llame a la función  <em>abreConexion()</em> una vez que se haya terminado de mostrar el componente. También observa cómo estamos incluyendo el código de <em>EditarBorrarCliente.as</em>:</p>
<pre class="brush: as3;">
&lt;mx:Script source=&quot;../actionscript/EditarBorrarCliente.as&quot;/&gt;
</pre>
<p>También presta atención en la forma en que estamos creando los <strong>renderers </strong>para las columnas.</p>
<pre class="brush: as3;">
&lt;mx:DataGridColumn sortable=&quot;false&quot; width=&quot;85&quot; textAlign=&quot;center&quot; headerText=&quot;Modificar&quot; dataField=&quot;modificar&quot;&gt;
&lt;mx:itemRenderer&gt;
		&lt;mx:Component&gt;
			&lt;mx:HBox horizontalAlign=&quot;center&quot;&gt;
			&lt;mx:Button id=&quot;editarBtn&quot; click=&quot;outerDocument.editarCliente(data.id_cliente, data.nombre, data.direccion, data.telefono, data.correo)&quot; label=&quot;&quot; height=&quot;20&quot; width=&quot;30&quot; icon=&quot;@Embed(source='../images/edit.png')&quot;/&gt;
			&lt;/mx:HBox&gt;
		&lt;/mx:Component&gt;
	&lt;/mx:itemRenderer&gt;
&lt;/mx:DataGridColumn&gt;
</pre>
<p>Dentro de los tags  <strong>&lt;mx:itemRenderer&gt; </strong>y  <strong>&lt;/mx:itemRenderer&gt; </strong>estamos usando como <em>layout </em>el <strong>HBox </strong>(HorizontalBox), aunque en realidad no afecta mucho ya que sólo estamos poniendo un componente por cada celda (en caso de que pongamos más elementos en esa celda, estos elementos se mostrarán uno tras otro de izquierda a derecha). El componente que estamos insertando en cada celda es un botón; este botón en el momento de hacer <strong>click</strong> sobre él llamará a la función <em>editarCliente</em>, el cual recibe como parámetros el ID, nombre, dirección, teléfono y correo del cliente en cuyo registro hicimos click. La palabra reservada <strong>outerDocument </strong>nos permite acceder a elementos que se encuentran fueran del alcance del item renderer. Además, al botón le estamos asignando el icono edit.png (<img align="absmiddle" src="http://www.codigometropoli.com/images/screens/edit.png" alt="" width="16" height="16" />) que está dentro de nuestra carpeta <em>images</em>. Importante: Observa cómo a esta columna del DataGrid le estamos especificando que no se pueda ordenar (sortable = false). Esto es porque en realidad no le estamos asignando valor alguno a cada celda, por lo tanto si intentáramos ordenar los registros de acuerdo a esta columna, Flex nos desplegaría un error.</p>
<p>El código para la columna que llevará los botones de <em>Eliminar </em>es el siguiente:</p>
<pre class="brush: as3;">
&lt;mx:DataGridColumn sortable=&quot;false&quot; width=&quot;80&quot; textAlign=&quot;center&quot; headerText=&quot;Eliminar&quot; dataField=&quot;eliminar&quot;&gt;
	&lt;mx:itemRenderer&gt;
	&lt;mx:Component&gt;
		&lt;mx:HBox horizontalAlign=&quot;center&quot;&gt;
			&lt;mx:Button id=&quot;borrarBtn&quot; click=&quot;outerDocument.borrarCliente(data.id_cliente)&quot; label=&quot;&quot; height=&quot;20&quot; width=&quot;30&quot; icon=&quot;@Embed(source='../images/remove.png')&quot;/&gt;
		&lt;/mx:HBox&gt;
	&lt;/mx:Component&gt;
	&lt;/mx:itemRenderer&gt;
&lt;/mx:DataGridColumn&gt;
</pre>
<p>El código es similar al mostrado más arriba, lo único que cambia es que en esta ocasión el botón mandará a llamar a la función <em>borrarCliente</em>, pasándole como parámetro el ID del cliente. Además, el icono para este botón es remove.png (<img align="absmiddle" src="http://www.codigometropoli.com/images/screens/remove.png" alt="" width="16" height="16" />).</p>
<p>Antes de ver el código de las funciones <em>editarCliente </em>y <em>borrarCliente</em>, veremos cómo mostrar los registros de nuestra base de datos en el DataGrid. Para eso, el código que pegaré a continuación forma parte del archivo <strong>EditarBorrarCliente.as</strong>.</p>
<p>Primero, importamos las clases y declaramos las variables  que necesitamos. En el arreglo <em>data_provider</em> almacenaremos los datos obtenidos de nuestra consulta y lo asignaremos como <strong>dataProvider </strong>de nuestro DataGrid (<em>clientes_dg</em>). La variable <em>id_selected</em> nos servirá para almacenar el ID del registro seleccionado y posteriormente eliminarlo de la base de datos.</p>
<pre class="brush: as3;">
// ActionScript file

	import flash.data.SQLConnection;
	import flash.events.SQLErrorEvent;
	import flash.events.SQLEvent;

	import mx.controls.Alert;
	import mx.events.CloseEvent;
	import mx.events.ListEvent;

	private var conexion:SQLConnection;
	private var database:File;
	private var queryStatement:SQLStatement = new SQLStatement();
	[Bindable]
	private var data_provider:Array;
	private var id_selected:Number = 0;
</pre>
<p>La primera función que es llamada en esta sección es <em>abrirConexion</em>:</p>
<pre class="brush: as3;">
public function abreConexion():void {
	reseteaForma();
	Modificar_Cliente.visible = false;
	reiniciaVariables();
	clientes_dg.addEventListener(ListEvent.CHANGE, dgChangeHandler);

	database = new File(File.applicationStorageDirectory.nativePath + &quot;\database\clientesDB.sqlite&quot;);
	conexion = new SQLConnection();
	conexion.addEventListener(SQLEvent.OPEN, dbAbrirConexion);
	conexion.addEventListener(SQLErrorEvent.ERROR, dbErrorConexion);
	queryStatement.sqlConnection = conexion;
	conexion.open(database);
}
</pre>
<p>Dentro de <em>abreConexion </em>llamamos a la función <em>reseteaForma</em>, la cual se encarga de borrar los datos de la forma para la modificación de los datos.</p>
<pre class="brush: as3;">
private function reseteaForma():void {
	nombre_txt.text = &quot;&quot;;
	direccion_txt.text = &quot;&quot;;
	telefono_txt.text = &quot;&quot;;
	correo_txt.text = &quot;&quot;;
	escondeMensajes();
}
</pre>
<p>Después de llamar a la función <em>reseteaForma</em>, ocultamos el canvas <em>Modificar_Cliente</em> y llamamos a la función <em>reiniciaVariables</em>, la cual se encargará de resetear los arreglos para eliminar su contenido previo.</p>
<pre class="brush: as3;">
private function reiniciaVariables():void {
	clientes_dg.dataProvider = new Array();	// Reiniciamos el arreglo para eliminar su contenido
	data_provider = new Array(); // Reiniciamos el arreglo para eliminar su contenido
}
</pre>
<p>Posteriormente le asignamos al datagrid <em>clientes_dg</em> el listener del evento <strong>CHANGE</strong>. Este evento es lanzado cuando el usuario hace click en alguno de los registros del DataGrid. Cuando se genere este evento, el programa se encargará de esconder el cambas <em>Modificar_Cliente</em> (es posible que previamente el usuario le haya dado click al botón de <span style="text-decoration: underline;">Editar</span> en alguno de los registros, es por eso que nos aseguramos de esconder el Canvas). Además, almacenamos en la vaiable <em>id_selected</em> el <strong>ID</strong> del registro seleccionado; y, por último, escondemos los posibles mensajes que se le mostraron al usuario para que, cuando vuelva a darle click al botón <span style="text-decoration: underline;">Editar</span>, no se le muestren.</p>
<pre class="brush: as3;">
private function dgChangeHandler(event:ListEvent):void {
escondeMensajes();
	Modificar_Cliente.visible = false;
	id_selected = event.target.selectedItem.id_cliente;
}
</pre>
<p>El resto del código de la función <em>abreConexion</em> ya lo conoces de las entradas anteriores.<br />
Si no hubo ningún problema en la conexión a la base de datos, llamamos a la función <em>getClientes</em> para llenar el DataGrid con nuestros registros:</p>
<pre class="brush: as3;">
private function dbAbrirConexion(event:SQLEvent):void {
	getClientes();
}

private function getClientes():void {
	queryStatement.clearParameters();
	queryStatement.text = &quot;SELECT * FROM cliente ORDER BY nombre asc&quot;;

	try {
		queryStatement.execute();

		var result:SQLResult = queryStatement.getResult();
		if(result.data != null) {
		    var numResults:int = result.data.length;

		    for (var i:int = 0; i &lt; numResults; i++)
		    {
		    	var row:Object = result.data[i];

			data_provider.push({nombre:row.nombre, id_cliente:row.id, direccion:row.direccion, correo:row.email, telefono:row.telefono});
		    }

		    clientes_dg.dataProvider = data_provider;
		}
	}
	catch(error:SQLError) {
		trace(&quot;Error: &quot; + error.toString());
	}
}
</pre>
<p>Dentro del código de <em>getClientes</em> haremos la consulta a la tabla <span style="text-decoration: underline;">cliente</span> para obtener todos los registros de nuestra base. Nuestro query es muy sencillo, en él estamos seleccionando (SELECT)  todas las columnas (*) de la tabla <em>cliente </em>y le estamos diciendo que lo ordene (ORDER BY) de forma ascendente (asc)  de acuerdo a la columna <em>nombre</em>.</p>
<pre class="brush: sql;">
SELECT * FROM cliente ORDER BY nombre asc
</pre>
<p>Una vez que ejecutamos la consulta (queryStatement.execute()) obtenemos el resultado con la función <em>getResult</em>. Comprobamos que el resultado no sea vacío (result.data!= null) y obtenemos el total de registros obtenidos por medio de la propiedad <em>length</em>. Como ya sabemos cuántos registros nos regresó la consulta, haremos un ciclo <strong>for</strong> para almacenar los registros en nuestro arreglo <em>data_provider</em>. Finalmente estamos asignando el arreglo <em>data_provider</em> a la propiedad <strong>dataProvider </strong>del DataGrid. Importante: Si no comprendes esta parte donde llenamos el arreglo y se lo asignamos al DataGrid te recomiendo visitar la entrada sobre el <a href="http://www.codigometropoli.com/componente-datagrid/" target="_blank">Componente DataGrid</a> que publiqué anteriormente.</p>
<p>Hemos terminado la explicación de cómo realizar la consulta a la base de datos y mostrar los resultados en el DataGrid. Ahora veremos las funciones que habíamos dejado pendientes: <em>editarCliente </em>y <em>borrarCliente</em>.<br />
Como lo mencioné anteriormente, cuando el usuario hace click en el botón de Editar de alguno de los registros, la función <em>editarCliente </em>es llamada:</p>
<pre class="brush: as3;">
public function editarCliente(id_cliente:Number, nombre:String, direccion:String, telefono:String, correo:String):void {
	id_selected = id_cliente;
	nombre_txt.text = nombre;
	direccion_txt.text = direccion;
	telefono_txt.text = telefono;
	correo_txt.text = correo;
	Modificar_Cliente.visible = true;
}
</pre>
<p>Esta función recibe como parámetros el ID del cliente, su nombre, dirección, teléfono y correo, para posteriormente mostrarlo en el formulario del canvas <em>Modificar_Cliente</em>. Si el usuario hace click en el botón de <em>Cambiar</em>, la función es <em>validaForma </em>es ejecutada:</p>
<pre class="brush: as3;">
private function validaForma():void {
	escondeMensajes();
	if(nombre_txt.text == &quot;&quot;) {
		msj1.visible = true;
		nombre_txt.setFocus();
	}
	else if(direccion_txt.text == &quot;&quot;) {
		msj2.visible = true;
		direccion_txt.setFocus();
	}
	else if(telefono_txt.text == &quot;&quot;) {
		msj3.visible = true;
		telefono_txt.setFocus();
	}
	else if(correo_txt.text == &quot;&quot; || !mail(correo_txt.text)) {
		msj4.visible = true;
		correo_txt.setFocus();
	}
	else {
		updateCliente(id_selected);
	}
}
</pre>
<p>Esta función es similar a la que usamos en la <a href="http://www.codigometropoli.com/sistema-de-clientes-parte-ii/" target="_blank">entrada</a> anterior, simplemente estamos verificando que todos los datos fueron llenados y, en caso positivo, llamamos a la función <em>updateCliente</em>.</p>
<pre class="brush: as3;">
private function updateCliente(idCliente:Number):void {
	queryStatement.clearParameters();
	var sql:String = &quot;UPDATE `cliente` SET nombre = :nombre, direccion = :direccion, telefono = :telefono, email = :correo WHERE id = :idCliente&quot;;
	queryStatement.parameters[&quot;:nombre&quot;] = nombre_txt.text;
	queryStatement.parameters[&quot;:direccion&quot;] = direccion_txt.text;
	queryStatement.parameters[&quot;:telefono&quot;] = telefono_txt.text;
	queryStatement.parameters[&quot;:correo&quot;] = correo_txt.text;
	queryStatement.parameters[&quot;:idCliente&quot;] = idCliente;
	queryStatement.text = sql;

	try {
		queryStatement.execute();
		abreConexion();
	}
	catch(error:SQLError){
		trace(&quot;Error: &quot; + error.toString());
	}
}
</pre>
<p>Esta función recibe como parámetro el ID del registro seleccionado, crea el query para actualizar los datos del registro y los nuevos valores son pasados como parámetros a la sentencia SQL. Una vez que se ejecuta la sentencia llamamos nuevamente a la función <em>abreConexion </em>para que muestre todos los registros (incluyendo los nuevos) en el DataGrid.</p>
<p>La función <em>borrarCliente </em>es llamada cuando el usuario hace click en el botón de <em>Eliminar</em>:</p>
<pre class="brush: as3;">
public function borrarCliente(id_cliente:Number):void {
	id_selected = id_cliente;
	Alert.yesLabel = &quot;Sí&quot;;
	Alert.noLabel = &quot;No&quot;;
Alert.show(&quot;¿Desea eliminar este cliente?&quot;, &quot;Importante&quot;, 3, this, alertClickHandler);
}
</pre>
<p>Esta función recibe como parámetro el ID del registro seleccionado por el usuario. Además, muestra un mensaje de alerta pidiéndole al usuario que confirme si desea eliminar el registro. Observa que al método <em>show </em>le pasamos como parámetro el manejador de eventos que debe considerar (<em>alertClickHandler</em>). Este manejador de eventos revisa si la respuesta del usuario fue positiva o negativa. En caso de que el usuario haya hecho click en el botón de Sí, llamamos a la función <em>delCliente </em>pasándole como parámetro el ID del registro seleccionado.</p>
<pre class="brush: as3;">
private function alertClickHandler(event:CloseEvent):void {
if (event.detail == Alert.YES)
      	delCliente(id_selected);
}
</pre>
<p>La función <em>delCliente </em>se encarga de ejecutar el query para borrar el registro de la base de datos. A este query le estamos pasando el ID del registro que hay que eliminar. Después de ejecutar la sentencia llamamos nuevamente a la función <em>abreConexion </em>para mostrar todos los registros restantes de la base de datos en el DataGrid.</p>
<pre class="brush: as3;">
private function delCliente(id_cliente:Number):void {
	queryStatement.clearParameters();
	queryStatement.text = &quot;DELETE FROM cliente WHERE id = :id_cliente&quot;;
	queryStatement.parameters[&quot;:id_cliente&quot;] = id_cliente;

	try {
		queryStatement.execute();
		abreConexion();
	}
	catch(error:SQLError) {
		trace(&quot;Error: &quot; + error.toString());
	}
}
</pre>
<p>Hemos llegado al final de esta tercera parte; ya nada más nos queda pendiente la cuarta y última entrega.</p>
<div align="center" style="margin-top:0px"><script type="text/javascript"><!--
      google_ad_client = "pub-5808310808246221";
      /* 250x250, Posts */
      google_ad_slot = "8254875600";
      google_ad_width = 250;
      google_ad_height = 250;
// --></script><br />
<script src="http://pagead2.googlesyndication.com/pagead/show_ads.js" type="text/javascript"></script></div>
<div style="margin-top:40px; margin-bottom:30px;">
<p><strong>Enlaces recomendados:</strong></p>
<p>» <a href="http://livedocs.adobe.com/flex/3/html/help.html?content=SQL_01.html" target="_blank">Working with local SQL databases</a><br />
» <a href="http://livedocs.adobe.com/flex/3/langref/index.html" target="_blank">Adobe® Flex® 3 Language Reference</a></div>
]]></content:encoded>
			<wfw:commentRss>http://www.codigometropoli.com/sistema-de-clientes-parte-iii/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Sistema de Clientes (AIR y SQLite) Parte II (Insertar Registros)</title>
		<link>http://www.codigometropoli.com/sistema-de-clientes-parte-ii/</link>
		<comments>http://www.codigometropoli.com/sistema-de-clientes-parte-ii/#comments</comments>
		<pubDate>Mon, 01 Sep 2008 16:47:38 +0000</pubDate>
		<dc:creator>Carla Macías</dc:creator>
				<category><![CDATA[AIR]]></category>
		<category><![CDATA[Proyectos]]></category>
		<category><![CDATA[Base de datos]]></category>
		<category><![CDATA[Flex]]></category>
		<category><![CDATA[Proyecto]]></category>
		<category><![CDATA[Sistema]]></category>

		<guid isPermaLink="false">http://www.codigometropoli.com/?p=312</guid>
		<description><![CDATA[Esta es la segunda parte del proyecto &#8220;Sistema de Clientes&#8221; desarrollado en AIR con SQLite como administrador de base de datos. En la entrada anterior vimos cómo crear la base de datos (clientesDB.sqlite), y cómo llenar con algunos registros por default la tabla cliente. Esta entrada forma parte de un proyecto y los archivos de [...]]]></description>
			<content:encoded><![CDATA[<p><img class="alignright" style="float: right;" src="http://codigometropoli.com/images/air.png" alt="Adobe AIR" width="93" height="93" />Esta es la segunda parte del proyecto &#8220;Sistema de Clientes&#8221; desarrollado en AIR con SQLite como administrador de base de datos. En la <a href="http://www.codigometropoli.com/sistema-de-clientes-parte-i/" target="_blank">entrada</a> anterior vimos cómo crear la base de datos (<em>clientesDB.sqlite</em>), y cómo llenar con algunos registros por default la tabla cliente.<br />
Esta entrada forma parte de un proyecto y los archivos de éste los encontrarás cuando termine de publicar todas las partes (entradas). Recuerda que para este proyecto estamos usando Flex Builder 3, del cual puedes bajarte una versión de prueba del Flex Builder 3 <a href="https://www.adobe.com/cfusion/tdrc/index.cfm?product=flex" target="_blank">aquí</a>.<br />
<span id="more-312"></span></p>
<p>Como lo comenté en el post <a href="http://www.codigometropoli.com/sistema-de-clientes-parte-i/" target="_blank">anterior </a>, aquí mostraré solamente la información más importante y sobre la cual trata el tema, sin embargo el archivo fuente del proyecto está completo y tiene integrado todo lo que se mostrará en esta entrada, la <a href="http://www.codigometropoli.com/sistema-de-clientes-parte-i/" target="_blank">anterior</a> y en las siguientes, para así formar un proyecto completo. Dicho lo anterior, a continuación iniciaré la explicación sobre cómo insertar registros en una base SQLite.</p>
<p><span style="color: #ff0000;"><strong>Parte 2: Insertar registros en SQLite con AIR</strong></span></p>
<p>Recuerda que para mantener organizado el código de nuestro proyecto y para evitar que se pierdan con toda la información aquí mostrada, dividí el código del proyecto en archivos .as. Estos archivos estarán almacenados en la carpeta <em>actionscript</em>. La estructura de nuestro proyecto será la siguiente:</p>
<div align="center">
<div id="attachment_270" class="wp-caption aligncenter" style="width: 255px"><a href="http://www.codigometropoli.com/wp-content/uploads/2008/08/proy1image1.jpg"><img class="size-full wp-image-270" title="proy1image1" src="http://www.codigometropoli.com/wp-content/uploads/2008/08/proy1image1.jpg" alt="Imagen 1" width="245" height="373" /></a><p class="wp-caption-text">Imagen 1</p></div></div>
<p>Todas las interfaces de este proyecto están incluidas en la carpeta <em>componentes</em>. La interfaz para dar de alta un nuevo cliente está en el archivo <em>AltaCliente.mxml</em>. Esta interfaz será la siguiente:</p>
<div align="center"><div id="attachment_270" class="wp-caption aligncenter" style="width: 344px"><a href="http://www.codigometropoli.com/images/screens/proy1image3.jpg"><img class="size-full wp-image-270" title="proy1image1" src="http://www.codigometropoli.com/images/screens/proy1image3.jpg" alt="Imagen 1" width="334" height="274" /></a><p class="wp-caption-text">Imagen 2</p></div></div>
<p>Los IDs de cada uno de estos elementos son:</p>
<ul>
<li> nombre_txt</li>
<li>dirección_txt</li>
<li>telefono_txt</li>
<li>correo_txt</li>
</ul>
<p>El código del archivo <em>AltaCliente.mxml</em> es el siguiente:</p>
<pre class="brush: as3;">
&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
&lt;mx:Canvas show=&quot;abreConexion()&quot; xmlns:mx=&quot;http://www.adobe.com/2006/mxml&quot; width=&quot;100%&quot; height=&quot;100%&quot;&gt;
	&lt;mx:Script source=&quot;../actionscript/AltaCliente.as&quot;/&gt;
	&lt;mx:Label y=&quot;16&quot; text=&quot;Alta de Clientes&quot; textAlign=&quot;center&quot; fontWeight=&quot;bold&quot; fontSize=&quot;14&quot; fontFamily=&quot;Verdana&quot; color=&quot;#F64507&quot; width=&quot;212&quot; horizontalCenter=&quot;48&quot;/&gt;
	&lt;mx:TextInput y=&quot;57&quot; width=&quot;212&quot; height=&quot;21&quot; id=&quot;nombre_txt&quot; fontSize=&quot;10&quot; fontFamily=&quot;Verdana&quot; horizontalCenter=&quot;48&quot;/&gt;
	&lt;mx:TextArea y=&quot;88&quot; width=&quot;212&quot; height=&quot;69&quot; id=&quot;direccion_txt&quot; horizontalCenter=&quot;48&quot;/&gt;
	&lt;mx:TextInput y=&quot;168&quot; width=&quot;212&quot; height=&quot;21&quot; id=&quot;telefono_txt&quot; fontSize=&quot;10&quot; fontFamily=&quot;Verdana&quot; horizontalCenter=&quot;48&quot;/&gt;
	&lt;mx:TextInput y=&quot;197&quot; width=&quot;212&quot; height=&quot;21&quot; id=&quot;correo_txt&quot; fontSize=&quot;10&quot; fontFamily=&quot;Verdana&quot; horizontalCenter=&quot;48&quot;/&gt;
	&lt;mx:Label y=&quot;57&quot; text=&quot;Nombre:&quot; fontSize=&quot;12&quot; fontFamily=&quot;Verdana&quot; fontWeight=&quot;normal&quot; color=&quot;#000000&quot; width=&quot;101&quot; textAlign=&quot;right&quot; horizontalCenter=&quot;-127&quot;/&gt;
	&lt;mx:Label y=&quot;93&quot; text=&quot;Dirección:&quot; fontSize=&quot;12&quot; fontFamily=&quot;Verdana&quot; fontWeight=&quot;normal&quot; color=&quot;#000000&quot; width=&quot;101&quot; textAlign=&quot;right&quot; horizontalCenter=&quot;-127&quot;/&gt;
	&lt;mx:Label y=&quot;168&quot; text=&quot;Teléfono:&quot; fontSize=&quot;12&quot; fontFamily=&quot;Verdana&quot; fontWeight=&quot;normal&quot; color=&quot;#000000&quot; width=&quot;101&quot; textAlign=&quot;right&quot; horizontalCenter=&quot;-127&quot;/&gt;
	&lt;mx:Label y=&quot;197&quot; text=&quot;Correo:&quot; fontSize=&quot;12&quot; fontFamily=&quot;Verdana&quot; fontWeight=&quot;normal&quot; color=&quot;#000000&quot; width=&quot;101&quot; textAlign=&quot;right&quot; horizontalCenter=&quot;-127&quot;/&gt;
	&lt;mx:Button y=&quot;230&quot; label=&quot;Aceptar&quot; width=&quot;100&quot; horizontalCenter=&quot;104&quot; click=&quot;{validaForma();}&quot;/&gt;
	&lt;mx:Label y=&quot;57&quot; text=&quot;(*)&quot; fontSize=&quot;10&quot; fontFamily=&quot;Verdana&quot; fontWeight=&quot;bold&quot; color=&quot;#B80808&quot; width=&quot;27&quot; textAlign=&quot;left&quot; id=&quot;msj1&quot; visible=&quot;false&quot; horizontalCenter=&quot;171&quot;/&gt;
	&lt;mx:Label y=&quot;89&quot; text=&quot;(*)&quot; fontSize=&quot;10&quot; fontFamily=&quot;Verdana&quot; fontWeight=&quot;bold&quot; color=&quot;#B80808&quot; width=&quot;27&quot; textAlign=&quot;left&quot; id=&quot;msj2&quot; visible=&quot;false&quot; horizontalCenter=&quot;171&quot;/&gt;
	&lt;mx:Label y=&quot;168&quot; text=&quot;(*)&quot; fontSize=&quot;10&quot; fontFamily=&quot;Verdana&quot; fontWeight=&quot;bold&quot; color=&quot;#B80808&quot; width=&quot;27&quot; textAlign=&quot;left&quot; id=&quot;msj3&quot; visible=&quot;false&quot; horizontalCenter=&quot;171&quot;/&gt;
	&lt;mx:Label y=&quot;197&quot; text=&quot;(*)&quot; fontSize=&quot;10&quot; fontFamily=&quot;Verdana&quot; fontWeight=&quot;bold&quot; color=&quot;#B80808&quot; width=&quot;27&quot; textAlign=&quot;left&quot; id=&quot;msj4&quot; visible=&quot;false&quot; horizontalCenter=&quot;171&quot;/&gt;
&lt;/mx:Canvas&gt;
</pre>
<p>Observa en el código anterior que el tag principal de este archivo es  <strong>&lt;mx:Canvas&gt;</strong> y no <strong>&lt;mx:WindowedApplication&gt;</strong>, esto es porque todas las interfaces que están dentro del directorio <em>componentes </em>las desplegaremos dentro de la aplicación principal (<em>Sistema_Clientes.mxml</em>); a la propiedad <strong>show </strong>del <strong>Canvas </strong>le estamos especificando que llame a la función  <em>abreConexion()</em> una vez que se haya terminado de mostrar el componente. También observa cómo estamos incluyendo el código de <em>AltaCliente.as</em>:</p>
<pre class="brush: as3;">
&lt;mx:Script source=&quot;../actionscript/AltaCliente.as&quot;/&gt;
</pre>
<p>Otro punto importante a destacar del código anterior es el botón que tiene de etiqueta “Aceptar”, cuando se produce un click en este botón llamaremos a la función <em>validaForma()</em> para asegurarnos que todos los datos requeridos sean llenados.</p>
<pre class="brush: as3;">
&lt;mx:Button y=&quot;230&quot; label=&quot;Aceptar&quot; width=&quot;100&quot; horizontalCenter=&quot;104&quot; click=&quot;{validaForma();}&quot;/&gt;
</pre>
<p>A continuación está la explicación del código del archivo <strong>AltaCliente.as</strong>:</p>
<pre class="brush: as3;">
import flash.data.SQLConnection;
import flash.events.SQLErrorEvent;
import flash.events.SQLEvent;
import mx.controls.Alert; /* Haremos uso de los mensajes de alerta, por lo que de una vez añadimos la clase */

private var conexion:SQLConnection; // Nuestro objeto de la clase SQLConnection
private var database:File; /* Aquí guardaremos la referencia de nuestro archivo .sqlite que es nuestra base de datos */
private var queryStatement:SQLStatement = new SQLStatement(); /* Creamos una variable de tipo SQLStatement en la cual estableceremos los queries y parámetros de nuestras consultas */

public function abreConexion():void {
	nombre_txt.setFocus();
	database = new File(File.applicationStorageDirectory.nativePath + &quot;\database\clientesDB.sqlite&quot;);
	conexion = new SQLConnection();
	conexion.addEventListener(SQLEvent.OPEN, dbAbrirConexion);
	conexion.addEventListener(SQLErrorEvent.ERROR, dbErrorConexion);
	conexion.open(database);
	queryStatement.sqlConnection = conexion;
}
</pre>
<p>Del código anterior, las seis primeras líneas no cambian en nada con respecto al código mostrado en el primer post. Cuando se llame la función <em>abreConexion</em> posicionaremos el cursor dentro del campo de texto nombre_txt, establecemos cuál es el archivo de la base de datos e intentamos abrirla; si existiera algún error es llamada la función dbErrorConexion; en caso contrario, es llamada la función dbErrorConexion.</p>
<p>En esta ocasión, la función <strong>abreConexion</strong> será llamada desde la intefaz que mostré más arriba (desde el archivo <em>AltaCliente.mxml</em>).</p>
<p>Como lo señalé más arriba, una vez que el usuario introduzca los datos y haga click en el botón de Aceptar, la función <em>validaForma()</em> será llamada, el código de esta función te lo presento a continuación:</p>
<pre class="brush: as3;">
private function validaForma():void {
	escondeMensajes();
	if(nombre_txt.text == &quot;&quot;) {
		msj1.visible = true;
		nombre_txt.setFocus();
	}
	else if(direccion_txt.text == &quot;&quot;) {
		msj2.visible = true;
		direccion_txt.setFocus();
	}
	else if(telefono_txt.text == &quot;&quot;) {
		msj3.visible = true;
		telefono_txt.setFocus();
	}
	else if(correo_txt.text == &quot;&quot; || !mail(correo_txt.text)) {
		msj4.visible = true;
		correo_txt.setFocus();
	}
	else
		compruebaCliente();
}
</pre>
<p>Dentro del código de <em>AltaCliente.mxml</em> están unas etiquetas con IDs <em>msj1</em>, <em>msj2</em>, <em>msj3</em>, etc. y cuyo texto es <strong>(*)</strong>; estas etiquetas nos permitirán mostrarle al usuario qué información le faltó por llenar. Como su nombre lo indica, la función <em>escondeMensajes</em> se encarga de &#8220;esconder&#8221; (visible = false) éstos mensajes y así mostrar solamente los que son necesarios.</p>
<p>En este ejemplo, tenemos cuatro sentencias <em>if</em> encargadas de verificar que la información en los campos de texto <em>nombre_txt</em>, <em>dirección_txt</em>, <em>telefono_txt</em> y <em>correo_txt</em> sean distintos de vacío. Además, nos aseguramos que el formato del correo electrónico sea correcto creando la función mail.</p>
<p>Finalmente, si ninguna de las cuatro condicionales <em>if</em> se cumple (es decir, toda la información requerida fue introducida) llamamos a la función <em>compruebaCliente</em> y verificar si el correo electrónico proporcionado ya existe en la base de datos.</p>
<p>A continuación, te muestro el código de las funciones <em>escondeMensajes</em>, <em>mail</em> y <em>compruebaCliente</em>:</p>
<pre class="brush: as3;">
private function escondeMensajes():void {
	msj1.visible = false;
	msj2.visible = false;
	msj3.visible = false;
	msj4.visible = false;
}

private function mail(email:String):Boolean
{
	var res:Boolean = false;
	if(email.indexOf(&quot;@&quot;)&gt;0 &amp;&amp; email.indexOf(&quot;@&quot;) == email.lastIndexOf(&quot;@&quot;))
	{
		if(email.lastIndexOf(&quot;.&quot;)&gt;email.indexOf(&quot;@&quot;) &amp;&amp; email.lastIndexOf(&quot;.&quot;)&lt;email.length-1)
		{
			res = true;
		}
	}
	return res;
}

private function compruebaCliente():void {
	var correo:String = correo_txt.text;

	queryStatement.clearParameters();
	queryStatement.text = &quot;SELECT 1 FROM cliente WHERE email = :correo LIMIT 1&quot;;
	queryStatement.parameters[&quot;:correo&quot;] = correo;

	try {
		query.execute();

		var result:SQLResult = query.getResult();

		if(result.data != null)
			Alert.show(&quot;Esa cuenta de correo ya existe&quot;);
		else
	       	insertaCliente();

	} catch(error:SQLError) {
		Alert.show(&quot;Error: “ + error.toString());
	}
}
</pre>
<p>Observa que dentro de la función <em>compruebaCliente</em> estamos declarando la variable <em>correo</em> y asignándole el valor del cuadro de texto <em>correo_txt</em>. Esta variable la pasaremos como parámetro a la consulta para verificar que esa cuenta de correo electrónico no exista en la base de datos. Con la función <strong>clearParameters</strong> de nuestro objeto <strong>SQLStatement</strong> estamos eliminando los posibles parámetros que hayamos asignado con anterioridad, de no hacer esto el programa generará un error indicándonos que la cantidad de parámetros establecidos en el query no concuerda con los parámetros del <strong>SQLStatement</strong>. A esta variable le indicamos a su propiedad <em>text</em> el <em>query</em> o la consulta que debe realizar. Además, le especificamos (dentro del query) que llevará el parámetro <em>:correo</em> y le asignamos a ese parámetro el valor de la variable <em>correo</em>.<br />
Por último, realizamos la ejecución de la consulta y verificamos si el resultado obtenido es distinto de vacío (nulo – null). Si el resultado es distinto de vacío quiere decir que sí existe un registro con esa cuenta de correo y por lo tanto mostramos un mensaje de alerta informándole al usuario; en caso contrario, llamamos a la función <em>insertaCliente()</em>:</p>
<pre class="brush: as3;">
private function insertaCliente():void {
	var sql:String = &quot;INSERT INTO `cliente` (nombre, direccion, telefono, email)&quot;;
	sql += &quot; VALUES (:nombre, :direccion, :telefono, :email) &quot;;
	queryStatement.clearParameters();
	queryStatement.parameters[&quot;:nombre&quot;] = nombre_txt.text;
	queryStatement.parameters[&quot;:direccion&quot;] = direccion_txt.text;
	queryStatement.parameters[&quot;:telefono&quot;] = telefono_txt.text;
	queryStatement.parameters[&quot;:email&quot;] = correo_txt.text;
	queryStatement.text = sql;

	try {
		queryStatement.execute();
		Alert.show(&quot;Sus datos han sido almacenados&quot;);
		restableceForma();
	}
	catch(error:SQLError){
		trace(&quot;Error: &quot; + error.toString());
	}
}
</pre>
<p>Creamos la variable sql y le asignamos un string con nuestra consulta y los parámetros que recibirá (recuerda que los parámetros son especificados con dos puntos &#8211; : -). Llamamos a la función <strong>clearParameters</strong> y posteriormente le asignamos al <strong>SQLStatement</strong> los valores de los cuatro parámetros (estos valores son obtenidos de nuestros campos de texto).  Ejecutamos la sentencia, le mostramos un mensaje al usuario informándole que sus datos han sido almacenados y por último llamamos a la función <em>restableceForma</em> para borrar la información de los campos de texto.</p>
<pre class="brush: as3;">
private function restableceForma():void {
	nombre_txt.text = &quot;&quot;;
	direccion_txt.text = &quot;&quot;;
	telefono_txt.text = &quot;&quot;;
	correo_txt.text = &quot;&quot;;
}
</pre>
<p>Hemos llegado al final de esta segunda parte. Si te perdiste la primera <a href="http://www.codigometropoli.com/sistema-de-clientes-parte-i/" target="_blank">parte</a> de este tutorial, te recuerdo que…  como recomendación y para que te asegures de que tu base de datos, la tabla y el registro fueron creados, puedes bajar el complemento para Firefox llamado <a href="https://addons.mozilla.org/es-ES/firefox/addon/5817" target="_blank"><strong>SQLite Manager</strong></a>, el cual es un pequeño y simple administrador de bases SQLite.</p>
<div align="center" style="margin-top:0px"><script type="text/javascript"><!--
      google_ad_client = "pub-5808310808246221";
      /* 250x250, Posts */
      google_ad_slot = "8254875600";
      google_ad_width = 250;
      google_ad_height = 250;
// --></script><br />
<script src="http://pagead2.googlesyndication.com/pagead/show_ads.js" type="text/javascript"></script></div>
<div style="margin-top:40px; margin-bottom:30px;"><strong>Enlaces recomendados:</strong><br />
<br />
» <a href="http://livedocs.adobe.com/flex/3/html/help.html?content=SQL_01.html" target="_blank">Working with local SQL databases</a><br />
» <a href="http://livedocs.adobe.com/flex/3/langref/index.html" target="_blank">Adobe® Flex® 3 Language Reference</a></div>
]]></content:encoded>
			<wfw:commentRss>http://www.codigometropoli.com/sistema-de-clientes-parte-ii/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Sistema de Clientes (AIR y SQLite) Parte I (Crear Base de datos)</title>
		<link>http://www.codigometropoli.com/sistema-de-clientes-parte-i/</link>
		<comments>http://www.codigometropoli.com/sistema-de-clientes-parte-i/#comments</comments>
		<pubDate>Tue, 26 Aug 2008 01:01:32 +0000</pubDate>
		<dc:creator>Carla Macías</dc:creator>
				<category><![CDATA[AIR]]></category>
		<category><![CDATA[Proyectos]]></category>
		<category><![CDATA[Base de datos]]></category>
		<category><![CDATA[Flex]]></category>
		<category><![CDATA[Proyecto]]></category>
		<category><![CDATA[Sistema]]></category>

		<guid isPermaLink="false">http://www.codigometropoli.com/?p=269</guid>
		<description><![CDATA[Esta es la primera parte del proyecto &#8220;Sistema de Clientes&#8221; desarrollado en AIR con SQLite como administrador de base de datos. Para este proyecto usaremos Flex Builder 3, del cual puedes bajarte una versión de prueba del Flex Builder 3 aquí. Si requieres más información sobre qué es AIR y qué puedes hacer con él [...]]]></description>
			<content:encoded><![CDATA[<p><img class="alignright" style="float: right;" src="http://codigometropoli.com/images/air.png" alt="Adobe AIR" width="93" height="93" />Esta es la primera parte del proyecto &#8220;Sistema de Clientes&#8221; desarrollado en AIR con SQLite como administrador de base de datos. Para este proyecto usaremos Flex Builder 3, del cual puedes bajarte una versión de prueba del Flex Builder 3 <a href="https://www.adobe.com/cfusion/tdrc/index.cfm?product=flex" target="_blank">aquí</a>. Si requieres más información sobre qué es AIR y qué puedes hacer con él visita esta entrada. Los archivos de este proyecto los encontrarás al terminar de publicar todas las partes (entradas) de este proyecto.<br />
<span id="more-269"></span><br />
Para este proyecto, abre Flex Builder 3 y crea un nuevo proyecto de AIR (File -&gt; New -&gt; Flex Project. Como nombre de proyecto (Project name) ponle <strong>Sistema_Clientes</strong>; en la sección de <em>Application type</em> selecciona la opción <strong>Desktop application</strong> (runs in Adobe AIR) y haz click en el botón <em>Finish</em>.<br />
Como lo comenté en la sección de <a href="http://www.codigometropoli.com/proyectos/">Proyectos</a>, aquí mostraré solamente la información más importante y sobre la cual trata el tema, sin embargo el archivo fuente del proyecto está completo y tiene integrado todo lo que se mostrará en esta entrada y en las siguientes, para así formar un proyecto completo. Dicho lo anterior, a continuación iniciaré la explicación sobre cómo crear una base de datos en SQLite.</p>
<p><span style="color: #ff0000;"><strong>Parte 1: Crear Base de Datos en SQLite con AIR<br />
</strong></span><br />
Para mantener organizado el código de nuestro proyecto y para evitar que se pierdan con toda la información aquí mostrada, vamos a dividir el código del proyecto en archivos .as. Estos archivos estarán almacenados en la carpeta <em>actionscript</em>. La estructura de nuestro proyecto será la siguiente:</p>
<div align="center"><div id="attachment_270" class="wp-caption aligncenter" style="width: 255px"><a href="http://www.codigometropoli.com/wp-content/uploads/2008/08/proy1image1.jpg"><img class="size-full wp-image-270" title="proy1image1" src="http://www.codigometropoli.com/wp-content/uploads/2008/08/proy1image1.jpg" alt="Imagen 1" width="245" height="373" /></a><p class="wp-caption-text">Imagen 1</p></div></div>
<p>Comenzamos con el archivo <strong>CrearBaseDatos</strong>.as:</p>
<p>Necesitamos de las siguientes librerías para poder tener acceso a los métodos de conexión con la base de datos, la ejecución de los queries, etc. Las clases que usaremos son SQLConnection, SQLErrorEvent y SQL Event:</p>
<pre class="brush: as3;">
import flash.data.SQLConnection;
import flash.events.SQLErrorEvent;
import flash.events.SQLEvent;
import mx.controls.Alert; /* Haremos uso de los mensajes de alerta, por lo que de una vez añadimos la clase */
</pre>
<p>Ahora vamos a crear los objetos de estas clases y las variables que requeriremos a lo largo de este archivo:</p>
<pre class="brush: as3;">
private var conexion:SQLConnection; // Nuestro objeto de la clase SQLConnection
private var database:File; /* Aquí guardaremos la referencia de nuestro archivo .sqlite que es nuestra base de datos */
private var existeBD:Boolean = false; /* Variable booleana en la cual guardaremos el valor de true si existe la base de datos y false en caso contrario */
private var queryStatement:SQLStatement = new SQLStatement(); /* Creamos una variable de tipo SQLStatement en la cual estableceremos los queries y parámetros de nuestras consultas */
</pre>
<p>Para crear las sentencias de SQL, necesitamos de un objeto de la clase <strong>SQLStatement</strong>, a este objeto lo llamamos <em>queryStatement</em>.</p>
<p>La función <strong>abreConexion </strong>(que mostraremos a continuación) será llamada desde la aplicación principal, es decir desde el archivo <em>Sistema_Clientes.mxml</em> (recuerda que al crear un nuevo proyecto, Flex Builder construye automáticamente un archivo MXML con el nombre del proyecto y el cual es el punto de partida de nuestra aplicación). Esta función se encargará de verificar si existe la base de datos la cual la pasamos como parámetro del constructor de la clase <strong>File</strong>.  Si no existiera la base de datos la aplicación se encargará de crearla. En caso contrario, se establecería la conexión con la base de datos.  El nombre de nuestra base de datos será <strong>clientesDB.sqlite</strong>, presta atención a la primera línea de nuestra función:</p>
<pre class="brush: as3;">
private function abreConexion():void {
	/* Asignamos a nuestra variable database el archivo de nuestra base de datos */
	database = new File(File.applicationStorageDirectory.nativePath + &quot;\database\clientesDB.sqlite&quot;);
	/* Inicializamos nuestra variable conexion */
	conexion = new SQLConnection();
	/* Creamos el listener que será llamado cuando se abra la conexión a la base de datos */
	conexion.addEventListener(SQLEvent.OPEN, dbAbrirConexion);
	/* Creamos el listener que será llamado cuando exista algún error en la conexión a la bd */
conexion.addEventListener(SQLErrorEvent.ERROR, dbErrorConexion);
queryStatement.sqlConnection = conexion; /* Le asignamos a su propiedad sqlConnection la variable conexion que creamos al inicio del archivo  */ 

	if(!database.exists) { // Comprobamos si existe o no la base de datos
		existeBD = false; // No existe la bd, por lo tanto le asignamos a existeBD el valor de falso
	    	conexion.open(database); // Abrimos la conexión a la bd
	}
	else {
	    	conexion.open(database); // Abrimos la conexión a la bd
	}
}
</pre>
<p>Observa que al constructor de la clase <strong>File </strong>le estamos pasando como parámetro el URL de donde estará almacenada nuestra base de datos. Para construir este URL estamos usando la propiedad <strong>applicationStorageDirectory</strong>, la cual hace referencia al directorio privado donde se encuentra la aplicación. Además, estamos usando la propiedad <strong>nativePath </strong>la cual nos regresa la ruta completa de acuerdo al sistema operativo donde se encuentra el sistema. A grandes rasgos, esta línea crea un directorio con el nombre de la aplicación (en este caso el directorio se llama <strong>Sistema_Clientes</strong>) dentro de la carpeta de Application Data (Datos de programa). Esta carpeta es donde los programas que tenemos instalados guardan información o las preferencias del usuario de la computadora. En Windows Vista, el directorio donde está almacenada la base de datos es C:\Users\Nombre_Usuario\AppData\Roaming\Sistema_Clientes. En Windows XP, el directorio es: C:\Documents and Settings\Nombre_Usuario\Datos de programa\Sistema_Clientes.</p>
<p>Al hacer la llamada a la función <strong>open</strong>, la función <strong>dbAbrirConexion </strong>será llamada en caso de que no exista error; en caso contrario la función <strong>dbErrorConexion </strong>será llamada. El código de estas funciones se muestra a continuación:</p>
<pre class="brush: as3;">
private function dbAbrirConexion(event:SQLEvent):void {
	if(!existeBD) { /* Si no existe la base de datos, llamamos a la función createTBLCliente */
		createTBLCliente();
	}
}

private function dbErrorConexion():void {
	Alert.show(&quot;No se pudo conectar a la base de datos&quot;); /* Mostramos un mensaje de error*/
}
</pre>
<p>Nuestra base de datos estará conformada por solamente una tabla (sólo para fines del ejercicio, ya que no es común que una base de datos esté formada por sólo una tabla). Nuestra tabla se llama <strong>cliente </strong>y sus elementos son los siguientes:</p>
<div align="center"><div id="attachment_272" class="wp-caption aligncenter" style="width: 390px"><a href="http://www.codigometropoli.com/wp-content/uploads/2008/08/proy1image2.jpg"><img class="size-full wp-image-272" title="proy1image2" src="http://www.codigometropoli.com/wp-content/uploads/2008/08/proy1image2.jpg" alt="Imagen 2" width="380" height="226" /></a><p class="wp-caption-text">Imagen 2</p></div></div>
<p>De la imagen anterior podemos determinar que el query para crear esta tabla es:</p>
<pre class="brush: sql;">
CREATE TABLE `cliente` (`id` INTEGER PRIMARY KEY  NOT NULL, `nombre` TEXT, `direccion` TEXT, `telefono` TEXT, `email` TEXT)
</pre>
<p>Este query lo usaremos en la función <strong>createTBLCliente</strong>, el cual es llamado desde <strong>dbAbrirConexion</strong>.</p>
<pre class="brush: as3;">
private function createTBLCliente():void {
	queryStatement.clearParameters();
	var sql:String = &quot;CREATE TABLE `cliente` &quot;;
	sql += &quot;(`id` INTEGER PRIMARY KEY  NOT NULL, `nombre` TEXT, `direccion` TEXT &quot;;
	sql += &quot;, `telefono` TEXT, `email` TEXT)&quot;;
	queryStatement.text = sql;
	try {
		queryStatement.execute();
		insertDefaultData();
	}
	catch(error:SQLError) {
		Alert.show(&quot;Error al insertar el registro: &quot; + error.toString());
	}
}
</pre>
<p>Para crear las sentencias de SQL, necesitamos de un objeto de la clase <strong>SQLStatement</strong>, a este objeto lo llamamos <em>queryStatement </em>y lo declaramos al inicio del programa. Para asegurarnos de que no tengamos parámetros asignados a este SQLStatement, usamos la función <strong>clearParameters</strong>, de no hacer esto el programa generará un error indicándonos que la cantidad de parámetros establecidos en el query no concuerda con los parámetros del <strong>SQLStatement</strong>. Posteriormente declaramos una variable <em>sql </em>de tipo <em>String</em> que contiene el query de crear la tabla de cliente.<br />
La propiedad <strong>text </strong>de la clase <strong>SQLStatement </strong>nos permite asignarle la sentencia SQL, por lo que le asignamos la variable <em>sql</em>.</p>
<p>Para poder &#8220;cachar&#8221; cualquier error que ocurra al ejecutar la sentencia, colocamos la llamada a la función <strong>execute </strong>dentro del bloque <strong>try</strong>. Cualquier error que ocurra será detectado y administrador en el bloque <strong>catch</strong>. En caso de que no exista ningún error al llamar a la función <strong>execute</strong>, llamaremos a la función <em>insertDefaultData </em>para insertar algunos registros por default.</p>
<p>A continuación pego el código de la función <em>insertDefaultData:</em></p>
<pre class="brush: as3;">
private function insertDefaultData():void {
	queryStatement.clearParameters();
	var sql:String = &quot;INSERT INTO `cliente` (nombre, direccion, telefono, email) VALUES (:nombre, :direccion, :telefono, :email)&quot;;
	queryStatement.parameters[&quot;:nombre&quot;] = 'Ernesto Trujillo';
	queryStatement.parameters[&quot;:direccion&quot;] = 'Avenida Importante #33';
	queryStatement.parameters[&quot;:telefono&quot;] = '55667788';
	queryStatement.parameters[&quot;:email&quot;] = 'etrujillo@email.com';
	queryStatement.text = sql;
	try {
		queryStatement.execute();
	}
	catch(error:SQLError) {
		Alert.show(&quot;Error al crear la tabla cliente: &quot; + error.toString());
	}
}
</pre>
<p>Este código es similar al de la función <em>createTBLCliente </em>en cuanto a la creación de la variable del <strong>SQLStatement</strong>, la creación del query y su asignación a la propiedad <strong>text</strong>. Sin embargo, presta atención en la forma en cómo se le pasan los valores al query; esto es usando dos puntos seguidos de un nombre cualquiera que quieras asignarle. Posteriormente debes establecer el valor de estos parámetros usando la propiedad <strong>parameters </strong>la cual recibe un arreglo asociativo con los valores del parámetro especificado.</p>
<p>Como recomendación y para que te asegures de que tu base de datos, la tabla y el registro fueron creados, puedes bajar el complemento para Firefox llamado <a href="https://addons.mozilla.org/es-ES/firefox/addon/5817" target="_blank"><strong>SQLite Manager</strong></a>, el cual es un pequeño y simple administrador de bases  SQLite.</p>
<div align="center" style="margin-top:0px"><script type="text/javascript"><!--
      google_ad_client = "pub-5808310808246221";
      /* 250x250, Posts */
      google_ad_slot = "8254875600";
      google_ad_width = 250;
      google_ad_height = 250;
// --></script><br />
<script src="http://pagead2.googlesyndication.com/pagead/show_ads.js" type="text/javascript"></script></div>
<div style="margin-top:40px; margin-bottom:30px;"><strong>Enlaces recomendados:</strong><br />
<br />
» <a href="http://livedocs.adobe.com/flex/3/html/help.html?content=SQL_01.html" target="_blank">Working with local SQL databases</a><br />
» <a href="http://livedocs.adobe.com/flex/3/langref/index.html" target="_blank">Adobe® Flex® 3 Language Reference</a></div>
]]></content:encoded>
			<wfw:commentRss>http://www.codigometropoli.com/sistema-de-clientes-parte-i/feed/</wfw:commentRss>
		<slash:comments>35</slash:comments>
		</item>
	</channel>
</rss>

