Herencia y reutilización de plantillas
La reutilización de plantillas y los mecanismos de herencia están aquí para aumentar tu productividad, ya que cada plantilla contiene sólo su contenido único y los elementos y estructuras repetidos se reutilizan. Introducimos tres conceptos: herencia de plantillas, reutilización horizontal y herencia de unidades.
El concepto de herencia de plantillas Latte es similar a la herencia de clases PHP. Se define una plantilla padre a partir de la cual otras plantillas hijas pueden extender y anular partes de la plantilla padre. Funciona muy bien cuando los elementos comparten una estructura común. ¿Suena complicado? No te preocupes, no lo es.
Herencia de diseño {layout}
Veamos la herencia de plantillas de diseño comenzando con un ejemplo. Esta es una plantilla padre que llamaremos por ejemplo
layout.latte
y define un documento HTML esqueleto.
La etiqueta {block}
define tres bloques que las plantillas hijas pueden rellenar. Todo lo que hace la etiqueta
block es decirle al motor de plantillas que una plantilla hija puede sobreescribir esas partes de la plantilla definiendo su
propio bloque con el mismo nombre.
Una plantilla hija podría tener este aspecto:
La etiqueta {layout}
es la clave aquí. Indica al motor de plantillas que esta plantilla „extiende“ otra
plantilla. Cuando Latte renderiza esta plantilla, primero localiza el padre – en este caso, layout.latte
.
En ese momento, el motor de plantillas se dará cuenta de las tres etiquetas de bloque en layout.latte
y
reemplazará esos bloques con el contenido de la plantilla hija. Tenga en cuenta que, dado que la plantilla hija no definió el
bloque footer, en su lugar se utiliza el contenido de la plantilla padre. El contenido de una etiqueta {block}
en una plantilla padre se utiliza siempre como alternativa.
El resultado podría ser el siguiente:
En una plantilla hija, los bloques sólo pueden situarse en el nivel superior o dentro de otro bloque, es decir:
Además, siempre se creará un bloque independientemente de si la condición {if}
que lo rodea se evalúa como
verdadera o falsa. Contrariamente a lo que podría pensarse, esta plantilla sí define un bloque.
Si desea que la salida dentro del bloque se muestre condicionalmente, utilice lo siguiente en su lugar:
Los datos fuera de un bloque en una plantilla hija se ejecutan antes de que se renderice la plantilla de diseño, por lo que
puede utilizarlo para definir variables como {var $foo = bar}
y propagar datos a toda la cadena de herencia:
Herencia multinivel
Puede utilizar tantos niveles de herencia como necesite. Una forma común de utilizar la herencia de diseño es el siguiente enfoque de tres niveles:
- Cree una plantilla
layout.latte
que contenga el aspecto principal de su sitio. - Cree una plantilla
layout-SECTIONNAME.latte
para cada sección de su sitio. Por ejemplo,layout-news.latte
,layout-blog.latte
, etc. Todas estas plantillas amplíanlayout.latte
e incluyen estilos/diseños específicos de cada sección. - Cree plantillas individuales para cada tipo de página, como un artículo de noticias o una entrada de blog. Estas plantillas amplían la plantilla de sección correspondiente.
Herencia de diseño dinámico
Puede utilizar una variable o cualquier expresión PHP como nombre de la plantilla padre, de forma que la herencia pueda comportarse dinámicamente:
También puede utilizar la API de Latte para elegir la plantilla de diseño de forma automática.
Consejos
Aquí tienes algunos consejos para trabajar con la herencia de diseños:
- Si utiliza
{layout}
en una plantilla, debe ser la primera etiqueta de plantilla en esa plantilla. - La maquetación puede buscarse automáticamente (como en los presentadores). En este caso, si la plantilla no
debe tener un diseño, lo indicará con la etiqueta
{layout none}
. - La etiqueta
{layout}
tiene el alias{extends}
. - El nombre de archivo de la plantilla extendida depende del cargador de plantillas.
- Puede tener tantos bloques como desee. Recuerde que las plantillas hijas no tienen por qué definir todos los bloques padres, por lo que puede rellenar valores por defecto razonables en una serie de bloques y luego definir sólo los que necesite más adelante.
Bloques {block}
Véase también anónimo {block}
Un bloque permite cambiar el modo en que se representa una parte determinada de una plantilla, pero no interfiere en modo alguno con la lógica que la rodea. Tomemos el siguiente ejemplo para ilustrar cómo funciona un bloque y, lo que es más importante, cómo no funciona:
Si renderiza esta plantilla, el resultado sería exactamente el mismo con o sin las etiquetas de bloque. Los bloques tienen acceso a variables de ámbitos externos. Es sólo una forma de hacerlo anulable por una plantilla hija:
Ahora, al renderizar la plantilla hija, el bucle va a utilizar el bloque definido en la plantilla hija child.Latte
en lugar del definido en la plantilla base parent.Latte
; la plantilla ejecutada es entonces equivalente a la
siguiente:
Sin embargo, si creamos una nueva variable dentro de un bloque con nombre o reemplazamos un valor de una existente, el cambio será visible sólo dentro del bloque:
El contenido del bloque puede modificarse mediante filtros. El siguiente ejemplo elimina todo el HTML y lo pone en mayúsculas:
La etiqueta también puede escribirse como n:attribute:
Bloques locales
Todos los bloques anulan el contenido del bloque padre del mismo nombre. Excepto los bloques locales. Son algo así como los métodos privados de una clase. Puedes crear una plantilla sin preocuparte de que, debido a la coincidencia de los nombres de los bloques, sean sobrescritos por la segunda plantilla.
Impresión de bloques {include}
Véase también {include file}
Para imprimir un bloque en un lugar determinado, utilice la etiqueta {include blockname}
:
También puede mostrar bloques de otra plantilla:
Los bloques impresos no tienen acceso a las variables del contexto activo, excepto si el bloque está definido en el mismo fichero donde se incluye. Sin embargo tienen acceso a las variables globales.
Puede pasar variables al bloque de la siguiente manera:
Puede utilizar una variable o cualquier expresión en PHP como nombre del bloque. En este caso, añada la palabra clave
block
antes de la variable, para que se sepa en tiempo de compilación que se trata de un bloque, y no de insertar plantilla, cuyo nombre también podría estar en la variable:
El bloque también puede imprimirse dentro de sí mismo, lo que resulta útil, por ejemplo, al representar una estructura de árbol:
En lugar de {include menu, ...}
también podemos escribir {include this, ...}
donde this
significa bloque actual.
El contenido impreso puede modificarse mediante filtros. El siguiente ejemplo elimina todo el HTML y lo pone en mayúsculas:
Bloque padre
Si necesita imprimir el contenido del bloque de la plantilla padre, la sentencia {include parent}
hará el truco.
Esto es útil si desea añadir algo al contenido de un bloque padre en lugar de sustituirlo por completo.
Definiciones {define}
Además de los bloques, en Latte también hay „definiciones“. Son comparables con las funciones en los lenguajes de programación regulares. Son útiles para reutilizar fragmentos de plantillas para no repetirse.
Latte intenta simplificar las cosas, así que básicamente las definiciones son lo mismo que los bloques, y todo lo que se dice sobre los bloques también se aplica a las definiciones. Se diferencian de los bloques en que:
- están encerradas en etiquetas
{define}
- sólo se muestran cuando se insertan a través de
{include}
- se pueden definir parámetros para ellas como las funciones en PHP
Imagina que tienes una plantilla de ayuda con una colección de definiciones sobre cómo dibujar formularios HTML.
Los argumentos de una definición son siempre opcionales con valor por defecto null
, a menos que se especifique un
valor por defecto (aquí 'text'
es el valor por defecto de $type
). También se pueden declarar tipos de
parámetros: {define input, string $name, ...}
.
La plantilla con las definiciones se carga utilizando {import}
. Las propias
definiciones se renderizan del mismo modo que los bloques:
Las definiciones no tienen acceso a las variables del contexto activo, pero sí a las variables globales.
Nombres de bloques dinámicos
Latte permite una gran flexibilidad en la definición de bloques porque el nombre del bloque puede ser cualquier expresión
PHP. Este ejemplo define tres bloques llamados hi-Peter
, hi-John
y hi-Mary
:
Por ejemplo, podemos redefinir sólo un bloque en una plantilla hija:
Así que la salida tendrá este aspecto:
Comprobación de la existencia de bloques {ifset}
Véase también {ifset $var}
Utilice la prueba {ifset blockname}
para comprobar si existe un bloque (o más bloques) en el contexto
actual:
Puede utilizar una variable o cualquier expresión en PHP como nombre del bloque. En este caso, añada la palabra clave
block
antes de la variable para dejar claro que no es la variable lo que
se comprueba:
La existencia de bloques también se devuelve mediante la función hasBlock()
:
Consejos
Aquí tienes algunos consejos para trabajar con bloques:
- El último bloque de nivel superior no necesita tener etiqueta de cierre (el bloque termina con el final del documento). Esto simplifica la escritura de plantillas hijo, que un bloque primario.
- Para una mayor legibilidad, puede dar opcionalmente un nombre a su etiqueta
{/block}
, por ejemplo{/block footer}
. Sin embargo, el nombre debe coincidir con el nombre del bloque. En plantillas más grandes, esta técnica ayuda a ver qué etiquetas de bloque se están cerrando. - No es posible definir directamente varias etiquetas de bloque con el mismo nombre en la misma plantilla. Pero se puede conseguir utilizando nombres de bloque dinámicos.
- Puede utilizar n:attributes para definir bloques
como
<h1 n:block=title>Welcome to my awesome homepage</h1>
- Los bloques también pueden utilizarse sin nombre sólo para aplicar los filtros a la
salida:
{block|strip} hello {/block}
Reutilización horizontal {import}
La reutilización horizontal es el tercer mecanismo de reutilización y herencia en Latte. Permite cargar bloques de otras
plantillas. Es similar a crear un archivo con funciones de ayuda en PHP y luego cargarlo usando require
.
Aunque la herencia del diseño de las plantillas es una de las características más potentes de Latte, está limitada a la herencia simple: una plantilla sólo puede extender a otra plantilla. La reutilización horizontal es una forma de lograr una herencia múltiple.
Tomemos un conjunto de definiciones de bloque:
Utilizando el comando {import}
, importe todos los bloques y definiciones definidos
en blocks.latte
a otra plantilla:
Si importa los bloques en la plantilla padre (es decir, si utiliza {import}
en layout.latte
), los
bloques también estarán disponibles en todas las plantillas hijas, lo que resulta muy práctico.
La plantilla que se pretende importar (por ejemplo, blocks.latte
) no debe ampliar otra plantilla, es decir, utilizar {layout}
. Sin embargo, puede importar
otras plantillas.
La etiqueta {import}
debe ser la primera etiqueta de plantilla después de {layout}
. El nombre de la
plantilla puede ser cualquier expresión PHP:
Puede utilizar tantas expresiones {import}
como desee en una plantilla determinada. Si dos plantillas importadas
definen el mismo bloque, gana la primera. Sin embargo, la mayor prioridad la tiene la plantilla principal, que puede sobrescribir
cualquier bloque importado.
El contenido de los bloques sobrescritos puede conservarse insertando el bloque del mismo modo que un bloque padre:
En este ejemplo, {include parent}
llamará correctamente al bloque sidebar
desde la plantilla
blocks.latte
.
Herencia de unidades {embed}
La herencia de unidades lleva la idea de la herencia de diseño al nivel de los fragmentos de contenido. Mientras que la herencia de maquetación funciona con „esqueletos de documento“, a los que dan vida plantillas hijas, la herencia de unidades te permite crear esqueletos para unidades de contenido más pequeñas y reutilizarlos donde quieras.
En la herencia de unidades, la etiqueta {embed}
es la clave. Combina el comportamiento de {include}
y
{layout}
. Permite incluir el contenido de otra plantilla o bloque y, opcionalmente, pasar variables, al igual que
{include}
. También le permite anular cualquier bloque definido dentro de la plantilla incluida, como hace
{layout}
.
Por ejemplo, vamos a utilizar el elemento acordeón plegable. Echemos un vistazo al esqueleto del elemento en la plantilla
collapsible.latte
:
Las etiquetas {block}
definen dos bloques que las plantillas hijas pueden rellenar. Sí, como en el caso de la
plantilla padre en la plantilla de herencia de diseño. También puede ver $modifierClass
variable.
Vamos a utilizar nuestro elemento en la plantilla. Aquí es donde entra {embed}
. Es una pieza super potente que
nos permite hacer todas las cosas: incluir el contenido de la plantilla del elemento, añadirle variables y añadirle bloques con
HTML personalizado:
La salida podría parecerse a:
Los bloques dentro de etiquetas embed forman una capa separada independiente de otros bloques. Por lo tanto, pueden tener el
mismo nombre que el bloque fuera del embed y no se ven afectados de ninguna manera. Utilizando la etiqueta include dentro de las etiquetas {embed}
puede insertar bloques creados aquí, bloques
de la plantilla incrustada (que no son locales), y también bloques de la plantilla
principal que son locales. También puede importar bloques de otros archivos:
Las plantillas incrustadas no tienen acceso a las variables del contexto activo, pero sí a las variables globales.
Con {embed}
puede insertar no sólo plantillas sino también otros bloques, por lo que el ejemplo anterior podría
escribirse así:
Si pasamos una expresión a {embed}
y no está claro si es un bloque o un nombre de archivo, añada la palabra
clave block
o file
:
Casos de uso
Existen varios tipos de herencia y reutilización de código en Latte. Vamos a resumir los conceptos principales para mayor claridad:
{include template}
Caso de uso: Usando header.latte
& footer.latte
dentro de layout.latte
.
header.latte
footer.latte
layout.latte
{layout}
Caso práctico: Extensión de layout.latte
dentro de homepage.latte
y
about.latte
.
layout.latte
homepage.latte
about.latte
{import}
Caso de uso: sidebar.latte
en single.product.latte
&
single.service.latte
.
sidebar.latte
single.product.latte
single.service.latte
{define}
Caso de uso: Una función que obtiene algunas variables y produce algunas marcas.
form.latte
profile.service.latte
{embed}
Caso práctico: Incrustación de pagination.latte
en product.table.latte
y
service.table.latte
.
pagination.latte
product.table.latte
service.table.latte