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 = 1Donde 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", 1 );
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