Crear templates para consultas SQL

Los "templates" o "plantillas" nos sirven para disponer de una estructura base y agregarle solo la información que cambia o varía, evitando tener que volver a copiar código una y otra vez.

En el caso de HTML podríamos usar Smarty, lo que nos permite contar con archivos de extensión .tpl y separar el código de presentación del código que se encargaría de armar o recibir información de la lógica de nuestro sistema.

Me ha sucedido que en muchos proyectos relacionados con web y con PHP se tienen que trabajar intensamente con consultas sql, más allá del tema de usar o no una capa de abstracción para conectarse a la base de datos. En estas situaciones existe mucho trabajo del lado del rol de DBA para incorporar mucha lógica en el motor de base de datos, como ser restricciones de integridad, disparadores, vistas, etc. De la misma forma, muchas reglas del negocio se resuelven a través de complejas consultas SQL que escapan del entendimiento de muchos de los programadores tradicionales (cabe aclarar que un programador nace con un cerebro distinto al de un DBA; muchas veces odiamos a las bases de datos y todo lo relacionado con la teoría de conjuntos ;-)).

En estos casos conviene que las consultas vengan preparadas por el DBA y que el desarrollador solo tenga que ejecutarlas, en otros, directamente trabajar con vistas que nos oculten toda la complejidad del diseño de la estructura de datos. También se pueden aprovechar "procedimientos almacenados" para ejecutar consultas con solo entregar algunos parámetros.

Me ha sucedido en situaciones intermedias y menos complejas que me es útil manejar el concepto de templates pero aplicados a consultas SQL donde simplemente tengo almacenadas las consultas y les paso los parámetros que requieren para ejecutarse.

Un ejemplo sencillo sería:

SELECT * FROM usuarios WHERE id = 1

Donde si tuviera un código PHP tendría que hacer cosas como:

1  
<?php
2    
3  
function traerUsuario$id ){
4     
$sql "SELECT * FROM usuarios WHERE id = $id";
5  
6     
// ejecutar_sql( $sql );
7     // etc.
8    
9  
}
10    
11  
?> 



O alguna versión más POO como:

1  
<?php 
2  
3  
class Usuario{
4     function 
getId$id ){
5        
$sql "SELECT * FROM usuarios WHERE id = $id";
6        
// procesar consulta
7     
}
8  }
9  
10  
?> 



Ahora bien, ¿qué pasa si para todas mis tablas uso constantemente esta misma lógica, donde solo necesito cambiar el nombre de la tabla y mantengo siempre un campo id, y luego solo le paso distintos valores por parámetro?

Yo puedo procesar esta consulta como un template, armando el marco para la sentencia y luego sustituyendo las "marcas" por valores, simplemente así:

1  
<?php 
2  
3  $sql_one 
"SELECT * FROM %s WHERE id = %s ";
4  
$sql sprintf$sql_one"usuarios");
5  
6  
?>



Lo que sucede es que ahora tomará la sentencia sql y en cada %s ("s" por "String") sustituirá en orden por los valores que agregue a continuación, causando el resultado esperado:

$sql = "SELECT * FROM usuarios WHERE id = 1";

Y ahí podemos aumentar enormemente la complejidad de las consultas y podremos reutilizarlas todas las veces que queramos, más, si las tenemos almacenadas en un archivo aparte y que todo nuestro sistema las use. Llegado el caso, si hubiera que optimizarlas habría que modificar un solo archivo.

Otra cosa que se me ocurre es algo más parecido al patrón de diseño ActiveRecord, que nos solucionaría un poco la vida con la operación de nuestras clases de persistencia de objetos.

Por ejemplo, podría crearme una clase Persistente que fuera así (usaré PHP4 para demostrar que no hace falta gran uso del lenguaje para implementar la idea):

1  
<?php 
2  
3  
require_once( 'BaseDeDatos.class.php' )
4  
5  class 
Persistente {
6     var 
$id;
7     var 
$tabla;
8     var 
$orden;
9  
10     var 
$sql_one "SELECT * FROM %s WHERE id = %s ";
11     var 
$sql_all "SELECT * FROM %s ORDER BY %s ASC";
12  
13     function 
getId$id ){
14        
$sql sprintf$this->sql_one$this->tabla$id );
15  
16        
$bd = new BaseDeDatos();
17        
$datos $bd->traerTodo$sql );
18        
$this->cargarDatos$datos );
19     }
20     function 
cargarDatos$datos ){
21        foreach( 
$datos as $key => $it ){
22           
$this->$key $it;
23        }
24     }
25     function 
getAll(){
26        
$sql sprintf$this->sql_all$this->tabla$this->orden );
27  
28        
$bd = new BaseDeDatos();
29        
$datos $bd->traerTodo$sql );
30        return 
$datos
31     
}
32  } 
33  
34  
?>



¿Bien, y cómo se usaría? Me creo mi clase concreta de persistencia de objetos, por ejemplo Usuario, y simplemente defino la información particular de la misma:

1  
<?php 
2  
3  
require_once( 'Persistente.class.php' );
4  
5  class 
Usuario extends Persistente {
6  
7     function 
Usuario() {
8        
$this->tabla "usuarios";
9        
$this->orden "id";
10     }
11  } 
12  
13  
?>



Y listo, no debo decirle nada más. Ahora solo me basta usarla de esta forma:

Si quiero traerme a todos los usuarios

$usuario = new Usuario();
$datos = $usuario->getAll();


Y si quiero traerme solo a un usuario particular, basta con que la base de datos del usuario tenga los campos id, nombre y apellido para hacer dinámicamente lo siguiente:

$usuario = new Usuario();
$usuario->getId(1);

echo
"Mi nombre es {$usuario->nombre} y mi apellido
es {$usuario->apellido}"
;


Y lo más interesante es que en situaciones donde lo genérico puede quitarnos libertad de acción, simplemente con sobreescribir los valores de los atributos definidos en la clase Persistente pero del lado de la clase Usuario resolvemos algunas limitaciones:

1  
<?php 
2  
3  
require_once( 'Persistente.class.php' );
4  
5  class 
Usuario extends Persistente {
6  
7     function 
Usuario() {
8        
$this->tabla "usuarios";
9        
$this->orden "id";
10  
11        
// Agregamos un JOINs con otra tabla
12        
$this->sql_all "SELECT * FROM %s as u, 
telefonos as t WHERE u.id = t.idUsuario ORDER BY u.%s, t.id ASC"
;
13     }
14  }
15  
16  
?> 



Mmm... creo que hoy me fui muy lejos divagando... más adelante les comparto un ejemplo completo que incluye persistencia en todos sus casos (update, delete, etc).

Más información

- Manual oficial, comando sprintf

Presentación: "Construyendo Entornos de Desarrollo Escalables"

Buscando presentaciones sobre "gestión ágil", metodologías y en concreto sobre Scrum, me encontré con esta de casualidad. Muy interesante, se las comparto:

"Surforce CMS": nueva lista de tareas pendientes

Estoy en estos momentos ingresando en una planilla de Google Docs la lista de tareas pendientes a realizar sobre el CMS que estamos desarrollando de forma colaborativa, con el simple objetivo de aprender entre nosotros a usar Zend Framework.

Si quieres participar -necesitamos revitalizar el equipo de trabajo- esta es tú oportunidad; deberás simplemente y por cuenta propia (hay mucha información en este blog de cómo hacerlo):
  1. Reconstruir localmente el CMS
  2. Elegir alguna de las tareas pendientes
  3. Implementarla
  4. Enviarme por mail el código nuevo (un "diff" mostrando lo que se hizo)
Si es correcto y funcional, lo que enviaste será agregado al repositorio y tú al grupo oficial de desarrollo para seguir aprendiendo en equipo.

Demuestra que puedes lograrlo y estás dentro. ¡Suerte!

Herencia de clases y el "Principio de Liskov" (actualizado 15/10/2007)


En realidad se llama "Principio de sustitución de Liskov" y el nombre completo es Bárbara H. Liskov (sí, hay mujeres en la informática y han hecho grandes aportes ;-)).

A grandes rasgos dice que el famoso "es un" (is_a) que generalmente usan los docentes para enseñarnos "herencia de clases" no es suficiente.

No basta con "ser" hay que "comportarse como tal".


Generalmente hago el mismo chiste cuando trato el tema en un curso: "un docente es una persona, pero no basta, debe comportarse como tal".

Un ejemplo más real: Sistema de liquidación de sueldos

Si tienes un sistema que liquida sueldos, una clase base Empleado (con atributos como "sueldo" que se usa para calcular su pago) y subclases Gerente, Desarrollador, Administrativa y Becario (asumamos que el último no recibe ninguna remuneración).

Usas polimorfismo y en tu clase Administracion tienes un método liquidarSueldo donde recibirás objetos de tipo Empleado. Bien, cuando en un momento recibes de tu lista de empleados un becario... ¿qué debe hacer el sistema? (ya que haces el cálculo en base al valor que viene en el atributo sueldo y este es heredado por todos desde la clase Empleado).
  1. ¿Emitir un comprobante impreso pero con valor 0?
  2. ¿Agregar un "if" preguntando si es becario, y no hacer nada?
  3. etc

Supongamos que el 1) no es aceptable por el gasto de papel y te piden que no se impriman (no tiene sentido), pasamos al punto 2), agregamos un "if".

¿No estamos "codificando a fuego" nuestro sistema para un comportamiento particular?

Estamos rompiendo el polimorfismo, justamente, el patrón estratégico más importante que tiene la POO. Cada vez que tenemos que cambiar nuestro código generamos nuevos costos y nuevos posibles errores.

Por eso cada vez nos cuesta más desarrollar un sistema, hasta que tenemos que tirarlo y desarrollar otro de cero... y empezamos otra vez con los problemas del mal diseño (code smell).

La base teórica

Los principios de diseño te dicen que "desarrolla cerrado al cambio y abierto a la extensión" (Principio Open/Closed, "Abierto / Cerrado").

Por ejemplo, tu código debe ser reutilizable (¿no es la idea esencial de la OO?) y con solo agregar código -sin tocar el existente- lograrás adecuarte a los cambios, a los nuevos requerimientos. No te olvides que nuestro código lo usan muchos otros objetos, si este cambiara, generaría un efecto en cadena, posiblemente, dejando de funcionar lo ya existente y tener que modificar más objetos.

Esta forma de "extensión" es agregar más clases a la herencia y el método liquidarSueldo no se modifica, pero si tu no haces correctas herencias, no puedes hacer lo primero, por lo tanto tu sistema se degradará en cascada.

Esta simple tontería el autor demuestra con muchos ejemplos que hacer "herencia por herencia", "por reutilizar código", no es suficiente y genera grandes problemas en los diseños.

Es una de las razones que me ven de mal humor cuando veo que implementan herencia a los golpes, prueba y error, con el argumento solo de "reutilizar código"

La conclusión final es...

El problema es que la herencia está mal formulada y que el Becario no se comporta como un Empleado, por lo tanto no puede ir en esa estructura jerárquica, de lo contrario nos va a obligar a desarmar nuestro sistema para tratar de ajustarlo a un comportamiento no adecuado (agregando condiciones explícitas para el mismo, hardcode) y este empezará a dejar de ser reusable.

No se puede hacer herencia por herencia, para reusar código. No se puede hacer herencia simplemente por que un "Becario es un Empleado", hay que estar seguro que además de "ser" se comporte como tal.

Nuestro becario, ya que no cobra una remuneración, no pude pasar por el sistema de liquidación de sueldos. La solución no es ajustar el sistema de sueldos para que lo permita.

Anexo otro artículo relacionado: Herencia Múltiple en PHP5

Nota: este post está basado en una discusión presentada en Foros del Web

Parece que pasamos a las ligas mayores: ¡Namespaces en PHP 5.3!

Me comenta mi colega Julio Viana que se enteró a través del blog de Inwe una muy buena noticia: la disponibilidad en la rama 5.3 de desarrollo de los tan necesitados namespaces. Fue toda una sorpresa, ya que se discutía si estaría recién en la próxima versión 6, pero veo que se han dado cuenta que era una vergüenza no contar con tan básica funcionalidad (los que conocemos lenguajes que se usan en arquitecturas como Java o .Net sabemos que sin esto no se puede vivir).

Si quieres saber de qué te hablo, puedes leer los siguientes post:

Próximo martes, curso en Universidad ORT




Bajar folleto

Recuerda: a partir del año que viene PHP4 dejará de tener soporte y se generará una importante demanda de desarrolladores con conocimientos de PHP5, no solo para migrar, sino, para rehacer sistemas y convertirlos a Programación Orientada a Objetos (sí, bien tarde, cuando todo el mundo ya habla "objetos").

Lo más importante de PHP5 no es el lenguaje en sí ni las miles de funciones que incorpora, es que podrás trabajar por fin "Orientado a Objetos" como con los "lenguajes mayores", al estilo de Java.

Puedes estar en la cresta de la ola o dejarla pasar.

PD: no digas que no te avisé.

"Surforce CMS": primer prototipo cerrado


Les comparto el siguiente correo que envié a la lista donde participamos todos los "teamleaders" del equipo de desarrollo del taller -piloto- on-line:

"Primer prototipo terminado

Bueno, se hicieron muchos cambios (están todos registrados en los comentarios del log de svn).

Revisión 76

Recomendación a todos:

Hacer un update del repositorio y volver a reconstruir la base de datos de cero a partir del archivo 6_TODO.sql (tiene la base de datos completa y ahora con soporte UTF8). También hay que configurar el proyecto en Eclipse para que soporte el mismo formato.

Felicitaciones a todos por su trabajo y dedicación, en especial a Julio Viana (mi mano derecha ;-)) que se quedó conmigo hasta las 3am para hacer los últimos arreglos y "cableados a fuego" para cumplir en tiempo y forma con las fechas de entrega.

El prototipo fue entregado al cliente para su evaluación. En base a las correcciones que sugieran seguimos con la segunda etapa que culmina con un segundo prototipo para el 31 de agosto.

Lo que hay que hacer mientras tanto es un fuerte refactoring para corregir todos los errores que cometimos y poder continuar limpiamente.


Nuevamente, felicitaciones a todos y adelante! ;-)"

Como había comentado en su momento este desarrollo es "real", para un cliente real, con exigencias reales. El proyecto lo estamos trabajando principalmente con mi colega Julio Viana, pero vamos asignando tareas para intentar compartir entre quienes quieran participar (solo hace falta ganas de aprender y dedicación) de la experiencia y así entre todos poder más fácilmente aprender herramientas nuevas, como en este caso, Zend Framework.

El sitio donde se encuentran los fuentes es en Google Code (alojado como un proyecto libre y de licencia GPL) y el sitio de pruebas está en Surforce.

Desde ya agradezco a todos los que se han mantenido activos hasta el momento, pues con la retroalimentación todos aprendemos.

Los teamleader's

De los cuatro grupos de desarrollo que participan hasta el momento (con desarrolladores a su cargo):


Y quiero hacer menciones especiales a:

El "Robin" que todo "Batman" necesita, el mano derecha que se encarga de encontrar soluciones mágicas para tratar de cumplir con las fechas propuestas ;-)

A los colaboradores que han levantado el guante y participaron enviando código con funcionalidades que necesitábamos: Rodrigo Muñoz (que de ahora en más va a participar con nosotros) más todos los aportes de gurús latinoamericanos como Pablo Rigazzi (Ar) y Christopher Valderrama (Mx) que siempre nos aportan una luz cuando el camino de nuestro aprendizaje se hace más oscuro y no sabemos hacia donde ir.

Nuevamente, gracias a todos (espero no olvidar a nadie) y seguimos adelante, quedan aún dos meses para concluir con el taller ;-)

Si quieres participar, ya sabes qué debes hacer.

PD: me queda pendiente saludar y agradecer a cada uno de los desarrolladores de cada uno de los cuatro grupos de desarrollo, a no desesperar, quiero armar un post aparte sobre el tema ;-)

Faltan 24 días - Curso "Desarrollo de Sistemas Web con PHP 5" (duración: 4 meses)


Existe abundante información en este blog de lo que trata el curso, los temas que abordaremos , la forma de darlo, mi filosofía con respecto al desarrollo de sistemas y en particular sobre el mundo "PHP Profesional". Todo lo que recorreremos durante 4 meses se puede desprender perfectamente desde el primero al último de los artículos que publico regularmente aquí.

¿Entonces, qué puedo decir de nuevo? ;-)

Bien, desde ya que no hay un curso igual, no solo porque siempre trato de adecuarme al público que tengo en frente y tratar de canalizar todas sus expectativas, sino porque yo también aprendo durante el proceso de cada dictado, obteniendo más experiencia, conocimientos, variando las herramientas... el mundo cambia rápidamente y nosotros no podemos estar ajenos a ello.

En la primera versión del curso de este año, que ya casi termina (20 de agosto entrega de obligatorios y defensas), la propuesta fue desarrollar un sistema similar a Twitter (aquí el mío), buscando con ello que no solo "programen"... que entiendan lo que involucra "desarrollar sistemas", conocer el mercado y casos de éxito, entender qué es "Web 2.0" y qué no, plantear un negocio, definir una estrategia, ser rentables, los riesgos que involucra, cómo dividir los problemas en pequeñas partes, o cómo trabajar en equipo apoyados con herramientas especializadas para ello, trabajo a distancia, conceptos de Ingeniería de Software, y un largo etcétera.

Para la segunda versión del curso -Setiembre 2007- estoy manejando varias actualizaciones, entre ellas agregar una introducción a Zend Framework que incluye abordar en la práctica el patrón MVC (para que se vayan con lo último que se está trabajando en el mercado mundial), y como obligatorio ya estoy evaluando solicitar la implementación de un sistema de "contactos personales" (del estilo Match.com o Yahoo.com) que involucra muchos puntos interesantes y desafiantes (además de los clásicos, mayor incorporación de Ajax para las interfaces, el desarrollo de chats entre usuarios, mayor trabajo en equipo tratando de emular un proyecto real con varios desarrolladores en paralelo, etc).

En los próximos días más novedades... pero ve reservando ya tu lugar en Universidad ORT ;-)

Surforce-CMS: están disponibles los requerimientos y las primeras tareas

Se encuentra disponible en el wiki del proyecto información sobre los requerimientos del sistema y ya se hizo el primer contacto con cada grupo de desarrollo que se armó durante el taller.

Aquí es la parte donde los que se quedaron por el camino o perdido la oportunidad de participar puedan incorporarse a través de una "demostrada valía" ;-)

Quienes puedan enviarme mejoras, correcciones, funcionalidades prontas de nuestra lista de pendientes serán integrados como miembros activos del proyecto.

Les hago copia del mail que les envié a todos los líderes con las asignaciones de tareas:

Primeras asignaciones que deben estar prontas antes del 15 de agosto.

Muchas de ellas son triviales y se hace siguiendo las pautas existentes en el proyecto actual.

La filosofía de los ABMs es lo más KISS que puedo sugerir ;-)

Como ejemplo, las noticias o los usuarios que están actualmente implementados: si eres un visitante anónimo puedes ver el listado de usuarios y las noticias existentes, no así el resto de operaciones. Si ingresas al sistema (iniciar sesión), inmediatamente después de ingresar aparecen las opciones de Altas, Bajas y Modificaciones (al clásico estilo RoR que podemos ver en cualquier ejemplo).

El primer prototipo del CMS (para el 15 de agosto) hará todas las operaciones necesarias siguiendo este camino, por lo que las tareas siguientes será seguir los ejemplos codificados (noticias y usuarios):

  • Grupo 1 - ABM de Contenidos
  • Grupo 2 - ABM de Secciones
  • Grupo 3 - ABM de Configuraciones
  • Grupo 4 - ABM de Menú

Por ejemplo: en el caso del ABM de Menús ya existe un menú (a la izquierda del todas las pantallas del CMS) pero en la actualidad es código estático en un template. Deberán crear toda la estructura para administrar dinámicamente un típico menú. Si el usuario está registrado le aparecerán las mismas opciones que en los demás ejemplos, alrededor del menú existente (Nueva opción, modificar opción, etc).

Toda la información base se encuentra en el Wiki: http://code.google.com/p/surforce-cms/wiki/CMSRequerimientos

Los detalles, dudas, diseños, directivas, restricciones, los discutiremos en este foro.

Como siempre, KISS, pragmáticos, traten de hacer la solución más simple, dividan el problema en pequeños problemas muy pequeños y repartan a sus integrantes pequeñas partes para luego integrarlas.

Tenemos una semana y media para terminar este prototipo y pasar a la segunda etapa ;-)

Si no aprendemos con esto, no aprendemos con nada.

Bienvenidos al mundo real ;-)

Perfectamente algún líder, desarrollador o equipo completo puede desertar o ser directamente descartado por su inacción. Por consiguiente, si quieres participar, es tu oportunidad de demostrar que puedes unirte colaborando con cualquiera de las necesidades del proyecto.

Espero vuestros comentarios ;-)

Final del TallerPHP5: Desarrollar un CMS usando PHP5 + Zend Framework

Como había anunciado en un post anterior, ya está toda la infraestructura base para empezar a trabajar en equipo sobre un mini-proyecto de CMS aplicando lo aprendido hasta el momento y agregando ahora un atractivo más: el famoso Zend Framework.

La idea es trabajar estos tres últimos meses (agosto, setiembre y octubre, aproximadamente) en un proyecto que ya está liberado como "Software Libre" (GPL) y que nos permitirá compartir conocimientos y experiencias sobre un tema que está siendo muy requerido por todos los desarrolladores, como es el uso del patrón de diseño MVC y un framework que nos ayude a ser cada vez más productivos evitando caer constantemente en la "programación artesanal".

En este momento ya existe un dominio para hacer pruebas y pueden ingresar al mismo con cualquier usuario de la lista y con la password "clave".

De ahora en más iré empezando a subir información de diseño en el sitio de hosting de Google (especialmente pensado para proyectos libres), armar la lista de pendientes por desarrollar, fechas para los entregables, deadlines, lista de bugs por corregir, etc, etc.

A pesar que existen 4 grupos de desarrollo (cada uno con un teamleader), mi idea es que de ahora en más cualquiera puede participar y ser dado de alta como un integrante del proyecto (con la posibilidad de hacer cambios en el SVN, participar en uno de los grupos existentes, integrar las listas de correo de coordinación, etc) lo podrá hacer simplemente demostrando interés y capacidad para trabajar en el proyecto.

¿Cómo participar?

Ahora cualquier usuario puede reconstruir localmente este proyecto. Si ese usuario me contacta con soluciones, mejoras, correcciones de bugs, funcionalidades que tenemos pendientes por desarrollar, haré una evaluación de las mismas y posteriormente será integrado a un grupo bajo la tutela de un teamleader.

Un buen lugar para empezar es la lista de tareas pendientes

Si quieres participar, esta es tu oportunidad de aprender con nosotros y ser famoso ;-)

Espero vuestros comentarios y/o sugerencias.

Entradas populares