7. Desarrollo de aplicaciones en conexion con bases de datos
7. Desarrollo de aplicaciones en conexion con bases de datos Dataprix 27 Noviembre, 2009 - 11:34En la reunión mantenida con la dirección se examinaron muy cuidadosamente los análisis de los SGBD seleccionados. Al ser la diferencia de valoración tan leve, no fue fácil tomar una decisión, pero al final se decidió la implementación de la solución sobre el SGBD PostgreSQL.
Se decidió, también, hacer la implementación en PHP, abstrayéndonos del SGBD con el que trabajáramos. Así, en caso de que la mayor dificultad en la administración de PostgreSQL nos hiciera rectificar la decisión en el futuro, el tiempo de puesta en marcha del cambio sería mínimo.
Antes de iniciar la implantación, vamos a realizar unas pruebas conceptuales de la propia implementación que, después, pasaremos a un equipo de desarrollo interno para que haga el resto. En concreto, tomaremos algunas de las consultas vistas en el capítulo 3 y programaremos los scripts PHP de las páginas correspondientes, documentándolas al máximo para facilitar el trabajo al equipo de desarrollo.
En primer lugar, crearemos un fichero .php con la conexión a la base de datos, para incluirlo en todos los PHP que lo vayan a necesitar, y evitar, así, tener que repetir código cada vez. Esta acción también ayudará a mantener centralizados los datos de la conexión y, en caso de que debiéramos cambiar el usuario o la contraseña o cualquier otro dato de la conexión, sólo tendríamos que actualizar dicho fichero.
datosconexion.php
<?php
// Incluimos la librerÍa una vez instalada mediante PEAR
require_once `DB.php´;
// Creamos la conexión a la base de datos, en este caso PostgreSQL
$db =& DB::connect(`pgsql://usuario:password@servidor/basededatos´);
___________________________________________________________________________
// Comprobamos error en la conexión
if (DB::isError($db)) {
die($db->getMessage());
}
?>
a. Nuevo cliente. Página de resultado de la inserción de un nuevo cliente
<?php
// Incluimos el fichero con los datos de la conexión.
include_one `datosconexion.php´;
// Utilizamos el método quoteSmart() para evitar que determinados caracteres
// (intencionados o no) puedan romper la sintaxis de la sentencia SQL.
// El método insertará automáticamente comillas alrededor de las cadenas
// de texto, o tratará los valores NULL correctamente según el SGBD, etc.
$db->query("INSERT INTO CLIENTE VALUES ("
. $db->quoteSmart($_REQUEST[`nombre´]) . ","
. $db->quoteSmart($_REQUEST[`dni´]). ","
. $db->quoteSmart($_REQUEST[`telefono´]) . ","
. $db->quoteSmart($_REQUEST[`email´]) . ")");
if (DB::isError($db)) {
echo "<h2>Error al insertar el cliente</h2>";
die($db->getMessage());
}
$db->disconnect();
c. Cambio de estado de la petición:
<?php
include_once `datosconexion.php´;
// Vamos a trabajar con todas las operaciones de esta página en forma de
// transacción, ya que, si se produce un error al insertar una nota o un
// material, la petición puede quedar en un estado erróneo.
$db->>autoCommit(false);
// Le decimos a PHP que almacene en un buffer la salida, para poder así
// rectificar en caso de producirse un error. ob_start();
// Suponemos que los estados nos llegan directamente con los valores
// soportados por el dominio, por ejemplo, a partir de los valores
// fijos de un desplegable.
// Suponemos que la fecha de inicio y fecha de fin nos llegan en formato
// español dd/mm/yyyy y los convertimos a YYYY-mm-dd según ISO 8601.
// Suponemos que el tiempo empleado nos llega en dos campos, horas y minutos, de
// forma que concatenándolos e insertando un ":" en medio, obtenemos una
// hora en formato ISO 8601.
if (isset($_REQUEST[`fechainicio´]) && !empty($_REQUEST[`fechainicio´])) {
$fechainicio_array=split(“"/",$_REQUEST[`fechainicio´]);
$fechainciioDB=date("Y-M-d", mktime(0, 0, 0, $fechainicio[1], $fechainicio[0],
$fechainicio[2]));
} else {
$fechainicioDB=NULL;
}
if (isset($_REQUEST[`fechafin´]) && !empty($_REQUEST[`fechafin´])) {
$fechafin_array=split("/",$_REQUEST[`fechafin´]);
$fechafinDB=date("Y-M-d", mktime(0, 0, 0, $fechafin[1], $fechafin[0], $fechafin[2]));
} else {
$fechafinDB=NULL;
}
$db->query("UPDATE PETICION SET "
. "cliente=" . $db->quoteSmart($_REQUEST[`cliente´]) . ","
. "resumen=" . $db->quoteSmart($_REQUEST[`resumen´]) . ","
. "estado=" . $db->quoteSmart($_REQUEST[`estado´]) . ","
. "fechainicio=" . $db->quoteSmart($fechainicioDB) . ","
. "fechafin" . $db->quoteSmart($fechafinDB) . ","
. "tiempoempleado=". $db->quoteSmart($_REQUEST[`hora´] . ":"
. $_REQUEST[`minutos´]));
if (DB::isError($db)) {
echo "<h2>Error al insertar el cliente</h2>";
ob_flush();
die($db->getMessage());
} else {
echo "<h2>Petición actualizada correctamente</h2>";
}
// Comprobamos si han añadido alguna nota
if (isset($_REQUEST[`texto_nota´]) && !empty($_REQUEST[`texto_nota´])) {
// Tenemos el identificador de petición en $_REQUEST[`referencia´]
$db->query("INSERT INTO NOTA_PETICION VALUES ("
. $db->quoteSmart($_REQUEST[`referencia´]) . ","
. $db->quoteSmart($_REQUEST[`texto_nota´]) . ","
. $db->quoteSmart(date("Y-M-d",mktime())) . ","
. $db->quoteSmart($_REQUEST[`nifEmpleado´]) . ")");
if (DB::isError($db)) {
ob_clean();
echo "<h2>Error al insertar la nota. Datos de la petición no actualizados</h2>";
ob_flush();
$db->rollback();
die($db->getMessage());
} else {
echo "<h3>Nota actualizada correctamente";
}
}
</h3>
// Comprobamos si han añadido algún material+
if (isset($_REQUEST[`nombrematerial´]) && !empty($_REQUEST[`nombrematerial´])) {
// Tenemos el identificador de la petición en $_REQUEST[`referencia´]
$db->query("INSERT INTO MATERIAL_PETICION VALUES "
. $db->quoteSmart($_REQUEST[`nombrematerial´]) . ","
. $db->quoteSmart($_REQUEST[`referencia´]) . ","
. $db->quoteSmart($_REQUEST[`precio´]) . ","
. $db->quoteSmart($_REQUEST[`cantidad´]) . ")");
if (DB::isError($db)) {
ob_clean();
echo "<h2>Error al insertar el material. Datos de la petición no actualizados</h2>";
ob_flush();
$db->rollback();
die($db->getMessage());
} else {
echo "<h3>Material actualizado correctamente";
}
}
</h3>
$db->commit();
$ob_flush();
$db->disconnect();
?>
f. y g. Peticiones abiertas de un cliente y resumen de los materiales usados en cada una
<?php
include_once `datosconexion.php´;
// Buscamos las peticiones abiertas de un cliente
$res=$db->query("SELECT P.referencia, P.resumen, P.estado, P.fecharecepcion FROM PETICION P JOIN CLIENTE C ON P.cliente=C.nif WHERE ESTADO NOT IN (`Resuelta´, `Cerrada´) ORDER BY fecharecepcion");
if (DB::isError($db)) {
die($db->getMessage());
}
// Antes de empezar la iteración por las peticiones, vamos a preparar la consulta
// correspondiente a los materiales empleados en cada una.
$queryMaterial=$db->prepare("SELECT SUM(M.precio) as precioMateriales, COUNT(M.nombrematerial) numMateriales FROM MATERIAL_PETICION M WHERE M.peticion=?
");
if (DB::isError($db)) {
die($db->getMessage());
}
echo "<table>";
echo "<tr><th>Referencia</th><th>Resumen</th><th>Estado</th><th>Duración</th><th>
Fecharecepción</th><th>Precio materiales</th><th>Núm. materiales</th></tr>"; while($res->fetchInto($row,DB_FETCHMODE_ASSOC)) {
echo "<tr>";
echo "<td>" . $row[`referencia´] . "</td>";
echo "<td>" . $row[`resumen´] . "</td>";
echo "<td>" . $row[`estado´] . "</td>";
echo "<td>" . $row[`fecharecepcion´] . "</td>";
$resMaterial=$db->execute($queryMaterial,$row[`referencia´]);
if (DB::isError($db)) {
die($db->getMessage());
} else {
$res->fetchInto($rowMaterial,DB_FETCHMODE_ASSOC);
echo "<td>" . $rowMaterial[`precioMateriales´] . "</td>";
echo "<td>" . $rowMaterial[`numMateriales´] . "</td>";
}
echo "</tr>";
}
<code>
echo "
";
?>
Mediante estos tres ejemplos, disponemos ya de una base tanto de código, como de estilo y mecanismos de comprobación de error, para desarrollar el resto de la aplicación, sin tener en cuenta su diseño.
Hemos intentado escoger consultas y operaciones representativas del funcionamiento de la aplicación y, a la vez, que se correspondieran con las vistas en apartados anteriores. Además, hemos introducido algunas funciones PHP que suelen utilizarse en combinación con el trabajo en bases de datos para tipos concretos, y para el tratamiento de errores, para evitar que el usuario reciba información confusa en la página de resultados.