Construye un motor de plantillas casero en PHP

Publicado en Snippets · 27 julio 2019.

¿ Te animas a construir conmigo un motor de plantilla en PHP ?. No te preocupes, será unos minutos, te lo prometo.

Como sabrás, una plantilla es un texto con referencias externas. Ejemplo: “Hola, {{nombre}}. Tu pedido {{referencia}}, realizado el día {{fecha}}, se realizó correspondiente. ". Un motor de plantilla es una herramienta que reemplazará esas referencias externas( o cadenas de reemplazo ), usando los datos que le proporciones.

Existen multitud de motores de plantillas en PHP, la mayoría muchos más avanzado que el que haremos nosotros. Sin embargo, en casos muy simples( como para plantillas de emails ) usar esos motores de plantillas, será matar moscas a cañonazos.

Estructura básica y manejo de variables.

Lo primero es crear una clase que nos sirva de base para nuestro sistema de plantillas. ¿ Qué te parece si la creamos así ? ( espero que me puedas perdonar algún día por el nombre ).

ArrayObject es una clase de la SPL( Standard PHP Library. Incluída junto con PHP ) que nos proporciona manejo y almacenamiento de variables. Pruébalo:

Ya tenemos la mitad del trabajo hecho y apenas hemos escrito código. ¿ Qué te parece ?. Lo siguiente es hacer que Rastreator pueda recibir un texto con las referencias y reemplazarlas con los datos introducidos.

Parseo de variables

Llamaremos parsear un texto a analizar ese texto en busca de cadenas de reemplazo. También incluirémos en la definición( aunque estrictamente no sea así ) la acción de reemplazar las referencias por un valor( el que tenga la variable con el mismo nombre que la referencia encontrada ).

Para que sea fácil de encontrar una cadena de reemplazo, habrá que determinar un formato que nos permita distinguirlas del texto normal( que deberá quedar intacto ). Actualmente, el formato que más se usa para estos menesteres es: {{ referencia }}. Creo que es una buena opción. ¿ Qué te parece a ti ?. Veamos el código que he hecho, a ver qué opinas:

Podemos probar la clase con un código como:

Fíjate que en el método parse_text, usamos la función preg_replace_callback. Esta función lo que hace es buscar cadenas de reemplazo por un patrón y si las encuentra, las reemplaza por lo que le indique un callback( método return_var_value_from_tokens ). Veamos en más detalle lo que le pasamos a preg_replace_callback:

  • Un patrón de cadena, en nuestro caso: /{{(?P<var>.*)}}/, que se encarga de buscar todas las cadenas de tipo {{cadena_de_texto}}. Si la encuentra, preg_replace_callback la descompondrá en tokens( fragmentos ). Uno de ellos llamado “var”( de ahí el ?P<var> del patrón ) será el que contendrá la cadena de texto( que para nosotros corresponderá con el nombre de la variable ).
  • Una función que devuelva el reemplazo para los tokens encontrados. En nuestro caso return_var_value_from_tokens que coge el token ‘var’ como el nombre de variable y retorna el valor que tenga asignado esa variable en Rastreator. Si no la encuentra, retorna cadena vacía.
  • El texto sobre el que queremos parsear.

Soporte a vistas

La mayoría de los motores de plantillas trabaja con vistas. Es decir, con archivos de texto plano cuyo contenido es una plantilla. Normalmente estos archivos o vistas se encuentran dentro de un directorio llamado views.

En nuestro caso, las vistas estarán en el directorio views que cuelgue del directorio dónde está ubicada la clase de Rastreator. Además, tendrán extensión .tpl. Veamos dos ejemplos de vistas que además nos servirá como demo:

email.tpl

firma.tpl

Estas vistas podrían ser el contenido de un email que podría mandarse desde una tienda online. Ya que en una tienda puede haber distintos tipos de emails, he decidido separar la firma del contenido especifico del correo. Si lo hacemos así con todos los tipos de emails de la tienda, si algún día modificamos la firma sólo habrá que actualizarlo desde una vista.

A continuación, el nuevo código de Rastreator:

Los cambios en esta nueva versión han sido los siguientes:

  • En la línea 32, he cambiado la función preg_replace_callback por preg_replace_callback_array. La diferencia es que la primera sólo trabaja con un patrón( y su callback asociado ) y la segunda trabaja con multiples patrones( y sus callbacks asociados ) pasados como un array.
  • En la línea 29, he añadido soporte a una macro de reemplazo con formato {% include: nombre_vista_a_incluir %} que, como imaginarás, lo que hace es incluir el contenido parseado de una vista dentro de otra vista. El patrón correspondiente está en la línea 8. Su callback, desde línea 42 a 47 que básicamente llama al método parse_view pásandole el nombre de la vista especificada en la macro.
  • Por último, desde línea 12 a 23, el método parse_view que recibe el nombre de una vista en el directorio views y que obtiene el contenido para luego pasarlo a parse_text( que ya hemos visto ) antes de devolverlo.

Si estás confuso, espera que viéndolo en "funcionamiento" se verá mejor:

Fíjate, asignamos el valor a dos variables:name y referencia y luego le decimos a Rastreator que parsee la vista email.tpl que está en la carpeta views. Rastreator cogerá el contenido de email.tpl y sustiuirá en primer lugar {{name}} por Manuel y {{referencia}} por 20190729. Al llegar a la macro include, el motor de plantilla cogerá el contenido de firma.tpl que está bajo views y lo parseará( pero no encontrará variables de reemplazo ) y el resultado lo reemplazará por la macro. El resultado final sería:


Hola, Manuel,

Tu pedido se ha realizado corréctamente. La referencia de su pedido es 20190729

Un saludo

------

TuTiendaOn - La mejor tienda con los mejores precios

email: tutiendaon@trasweb.net


¿ Te gusta cómo queda ?. Si eres de los amantes del overengineering hay otra implementación basada en abstracciones.

Pues eso es todo, ¿ qué te ha parecido ?, ¿ qué quieres más ?:

  • Si llega a 7 like el tuit que he usado para anunciar la entrada, actualizaré la entrada para que Rastreator tenga la opción para parsear archivos.
  • Si llega a 14, añadiré a Rastreator para que funcione con variables con filtros. Ejemplo: {{ nombre | mayuscula }}.
  • Si llega a 21, añadiré a Rastreator para que funcione con formato en los filtros. Ejemplo: {{ fecha | format: ‘d/m/Y’ }} o {{ nombre | trim: ‘-’ }}
  • Si llega a 28, añadiré la opción de if.

La continuación la tenéis aquí: https://trasweb.net/snippets/construye-un-motor-de-plantillas-casero-en-php-ii

¡ Compártelo !
Este sitio utiliza cookies propias y de terceros para mejorar tu experiencia con el sitio web. Al continuar con la navegación consideramos que acepta su uso.