17.12.05

Crear formularios sencillos con la clase "HTML_Form"

Para este ejemplo vamos a asumir que estamos usando el motor de base de datos MySQL y una base de datos "prueba", donde crearemos un formulario para solicitar el id del cliente y luego consultar la base de datos para recuperar la información del mismo.

Debemos crear la tabla "clientes" que contendrá los siguientes campos: id y nombre.

Este es el código de nuestro "formulario.php":


<?php
require_once "HTML/Form.php";
$form = new HTML_Form('consulta.php');
$form->addText("id", "Número de cliente?");
$form->addSubmit("submit", "Consultar");
$form->display();
?>


Creamos nuestro primer formulario usando la clase "HTML_Form", donde en el constructor de la clase definimos cual será el programa que se encargará de procesar la información del formulario y hacer la consulta SQL (consulta.php). Creamos un campo para recibir el número de id (método addText) y el botón de "Consultar" (método addSubmit).

<?php
require_once 'DB.php';
$db =& DB::connect('mysql://root:@localhost/prueba');
if (PEAR::isError($db)) {
die($db->getMessage());
}

$db->setFetchMode(DB_FETCHMODE _ASSOC);
$sql = "SELECT * FROM clientes";
if($_GET['id']<>""){
$sql .= " WHERE id='".$_GET['id']."'";
}
$res =& $db->query($sql);

while ($res->fetchInto($row)) {
print_r($row);
}
?>

En el archivo "consulta.php" recibimos el valor cargado en el formulario ($_GET['id']) y si este tiene un valor (es distinto de cero) se crea una sentencia SQL para obtener el cliente, de lo contrario traerá todos los clientes.

Simple, directo y sencillo. Con el framework Pear pudimos armar la parte de la "presentación" (el formulario) y parte de la "persistencia" (con el resultado).

1.12.05

¿Cómo abstraer nuestra conexión con la base de datos?


En este pequeño ejemplo nos vamos a introducir en el uso del Framework PEAR", y en particular hemos seleccionado la "clase" (concepto de la programación orientada a objetos) para hacer la "abstracción de la base de datos".


La idea es tener "algo" entre medio de "nuestro sistema" y la "base de datos" que nos "oculte" la complejidad de la misma y toda dependencia con ella.


Si nosotros programáramos usando directamente las sentencias (o funciones) que nos provee el propio lenguaje, estaríamos atados de forma explícita a la base de datos.


Por ejemplo, disponemos de funciones como:



$con = mysql_connect($cadena_de_conexion);
$result = mysql_query('SELECT * FROM clientes', $con);
while ($row = mysql_fetch_row($result)) {
echo $row[0] . ': ' . $row[1] . "\n";
}
mysql_free_result($result);
msql_close();
?>


Este ejemplo está hecho con funciones donde explicitan cual es nuestra base de datos (mysql_connect, mysql_query, etc). Si en un futuro deseamos cambiar de motor a PostgreSQL (por ejemplo) deberíamos recorrer todos nuestros fuentes que usen la base y sustituir por las funciones correspondientes: pg_connect, pg_query.


Es evidente que volveríamos a tener el mismo problema si en un futuro necesitáramos cambiar nuevamente de base, por ejemplo, a Oracle.


Una solución es usar "algo" que nos "abstraiga" del trabajo con la base de datos; en este caso nos apoyaremos en una de las clases disponibles del Framework Pear: "DB"




require_once 'DB.php';
$db =& DB::connect('mysql://root:@localhost/prueba');
$result =& $db->query('SELECT * FROM clientes');
while ($result->fetchInto($row)) {
echo $row[0] . ': ' . $row[1] . "\n";
}
$db->free();
$db->disconnect();
?>


Si nos encontramos que debos cambiar de motor de base de datos, solo deberíamos cambiar cambiar el nombre de "motor" en la cadena de conexión (mysql -> pgsql).


Alguien podría decir que lo único que mejoramos es que en vez de cambiar muchas líneas explícitas sobre MySQL ahora debemos cambiar una (la cadena de conexión) en todos nuestros fuentes.


La idea es hacer un ejemplo rápido para explicar de forma fácil las ventajas de esta forma de trabajo. Se me ocurren tres alternativas rápidas para solucionar estos inconvenientes:



  • Creamos un archivo con la sintaxis de conexión y lo incluimos en todos nuestros fuentes. Cuando se necesite cambiar la cadena, solo se deberá modificar un solo fuente.

  • Creamos un archivo de configuración que define "constantes" y luego estas se usan en todas las cadenas de conexión.

  • Creamos nuestra propia clase "BaseDeDatos" que en su estructura tienen los atributos cargados con valores por defecto que definen como será nuestra conexión a la base. Modificamos los atributos de la clase, y cambia el comportamiento de la conexión.


La última opción es la que prefiero, pues agregamos una nueva capa de abstracción que nos abstrae ahora de la capa de abstracción de Pear (valga todo lo redundante que fui).

¿Cual es el beneficio de esto?

Estamos protegidos ante un nuevo potencial problema: que debamos cambiar la clase "DB" por otra que ofrezca mayores funcionalidades, lo que nos obligaría a modificar todos nuestros fuentes nuevamente y agregar la sintaxis de la nueva clase de abstracción!



¿Fantástico, no? ;-)



¡Saludos abstractos!