Cargadores de plantillas
Los cargadores son el mecanismo que utiliza Latte para recuperar el código fuente de sus plantillas. Lo más común es que las plantillas sean archivos almacenados en disco, pero el flexible sistema de cargadores de Latte le permite cargarlas desde prácticamente cualquier lugar, o incluso generarlas dinámicamente.
¿Qué es un cargador?
Normalmente, cuando se trabaja con plantillas, se piensa en .latte
archivos que residen en la estructura de
directorios del proyecto. Esto es manejado por el FileLoader por defecto de Latte. Sin embargo, la
conexión entre un nombre de plantilla (como 'main.latte'
o 'components/card.latte'
) y su contenido de
código fuente real no tiene que ser una asignación directa de ruta de archivo.
Aquí es donde entran en juego los cargadores. Un cargador es un objeto responsable de tomar un nombre de plantilla (una cadena
identificadora) y proporcionar a Latte su código fuente. Latte depende enteramente del cargador configurado para esta tarea. Esto
se aplica no sólo a la plantilla inicial solicitada a través de $latte->render('main.latte')
sino también a
cada plantilla referenciada dentro usando etiquetas como {include ...}
, {layout ...}
,
{embed ...}
, o {import ...}
.
¿Por qué utilizar un cargador personalizado?
- Obtener plantillas almacenadas en una base de datos, una caché (como Redis o Memcached), un sistema de control de versiones (como Git, basado en una confirmación específica) o generadas dinámicamente.
- Implementar convenciones de nomenclatura personalizadas:** Es posible que desee utilizar alias más cortos para las plantillas o implementar una lógica de ruta de búsqueda específica (por ejemplo, buscar primero en un directorio de temas y luego volver a un directorio predeterminado).
- Añadir seguridad o control de acceso: Un cargador personalizado podría verificar los permisos del usuario antes de cargar ciertas plantillas.
- Preprocesamiento: Aunque generalmente se desaconseja(los pases de compilador son mejores), un cargador podría teóricamente preprocesar el contenido de la plantilla antes de pasárselo a Latte.
Usted configura el cargador para su instancia Latte\Engine
usando el método setLoader()
:
$latte = new Latte\Engine;
// Utilizar el cargador de archivos predeterminado para los archivos de '/ruta/a/plantillas
$loader = new Latte\Loaders\FileLoader('/path/to/templates');
$latte->setLoader($loader);
Un cargador debe implementar la interfaz Latte\Loader
.
Cargadores incorporados
Latte proporciona varios cargadores estándar:
Cargador de archivos
Este es el cargador por defecto utilizado por Latte\Engine
si no se especifica otro cargador. Carga las
plantillas directamente desde el sistema de archivos.
Opcionalmente puede establecer un directorio raíz para restringir el acceso:
use Latte\Loaders\FileLoader;
// Lo siguiente sólo permitirá cargar plantillas dentro de /var/www/html/templates
$loader = new FileLoader('/var/www/html/templates');
$latte->setLoader($loader);
// $latte->render('../../../etc/passwd'); // Esto lanzaría una excepción
// Renderizar plantilla localizada en /var/www/html/templates/pages/contact.latte
$latte->render('pages/contact.latte');
Resuelve los nombres de plantilla relativos a la plantilla actual cuando se utilizan etiquetas como {include}
o
{layout}
, a menos que se indique una ruta absoluta.
StringLoader
Este cargador recupera el contenido de las plantillas desde un array asociativo donde las claves son los nombres de las plantillas (identificadores) y los valores son las cadenas del código fuente de las plantillas. Es particularmente útil para pruebas o pequeñas aplicaciones donde las plantillas pueden estar almacenadas dentro del propio código PHP.
use Latte\Loaders\StringLoader;
$loader = new StringLoader([
'main.latte' => 'Hello {$name}, include is below:{include helper.latte}',
'helper.latte' => '{var $x = 10}Included content: {$x}',
// Añada más plantillas según sea necesario
]);
$latte->setLoader($loader);
$latte->render('main.latte', ['name' => 'World']);
// Salidas: Hello World, include is below:Contenido incluido: 10
Si sólo necesita renderizar una única plantilla directamente desde una cadena sin necesitar includes o herencia
referenciando otras plantillas de cadena con nombre, puede pasar la cadena directamente a render()
o
renderToString()
cuando use StringLoader
sin un array:
$loader = new StringLoader;
$latte->setLoader($loader);
$templateString = 'Hello {$name}!';
$output = $latte->renderToString($templateString, ['name' => 'Alice']);
// $output contiene "¡Hola Alice!
Creación de un cargador personalizado
Para crear su propio cargador (por ejemplo, para cargar plantillas desde una base de datos, caché, control de versiones u otra fuente), necesita crear una clase que implemente la interfaz Latte\Loader.
Veamos qué debe hacer cada método.
getContent (string $name): string
Este es el método principal del cargador. Su responsabilidad es recuperar y devolver el contenido completo del código fuente
de la plantilla identificada por $name
(tal y como se pasó a $latte->render()
o fue devuelto por getReferredName()).
Si no se puede encontrar o acceder a la plantilla, este método debe lanzar un mensaje
Latte\RuntimeException
.
public function getContent(string $name): string
{
// Ejemplo: Recuperación de un hipotético almacenamiento interno
$content = $this->storage->read($name);
if ($content === null) {
throw new Latte\RuntimeException("Template '$name' cannot be loaded.");
}
return $content;
}
getReferredName (string $name, string $referringName): string
Este método maneja la resolución de nombres de plantillas usados dentro de etiquetas como {include}
,
{layout}
, etc. Cuando Latte encuentra, por ejemplo, {include 'partial.latte'}
dentro de
main.latte
, llama a este método con $name = 'partial.latte'
y
$referringName = 'main.latte'
.
El trabajo del método es resolver $name
en un identificador canónico (por ejemplo, una ruta absoluta, una clave
de base de datos única), que se utilizará al llamar a otros métodos del cargador, basándose en el contexto proporcionado por
$referringName
.
public function getReferredName(string $name, string $referringName): string
{
return ...;
}
getUniqueId (string $name): string
Latte utiliza la caché de plantillas compiladas para mejorar el rendimiento. Cada archivo de plantilla compilado necesita un
nombre único derivado del identificador de la plantilla fuente. Este método proporciona una cadena que identifica de
forma única la plantilla $name
.
Para plantillas basadas en archivos, la ruta absoluta puede funcionar. Para plantillas basadas en bases de datos, es común una combinación de un prefijo y el ID de la base de datos.
public function getUniqueId(string $name): string
{
return ...;
}
Ejemplo: Cargador de base de datos simple
Este ejemplo muestra la estructura básica de un cargador que recupera plantillas almacenadas en una tabla de base de datos
denominada templates
con las columnas name
(identificador único), content
, y
updated_at
.
use Latte;
class DatabaseLoader implements Latte\Loader
{
public function __construct(
private \PDO $db,
) {
}
public function getContent(string $name): string
{
$stmt = $this->db->prepare('SELECT content FROM templates WHERE name = ?');
$stmt->execute([$name]);
$content = $stmt->fetchColumn();
if ($content === false) {
throw new Latte\RuntimeException("Template '$name' not found in database.");
}
return $content;
}
// Este sencillo ejemplo asume que los nombres de las plantillas ('homepage', 'article', etc.)
// son IDs únicos y las plantillas no se referencian entre sí relativamente.
public function getReferredName(string $name, string $referringName): string
{
return $name;
}
public function getUniqueId(string $name): string
{
// El uso de un prefijo y el propio nombre es único y suficiente en este caso
return 'db_' . $name;
}
}
// Uso:
$pdo = new \PDO(/* connection details */);
$loader = new DatabaseLoader($pdo);
$latte->setLoader($loader);
$latte->render('homepage'); // Carga la plantilla con el nombre 'homepage' de la base de datos
Los cargadores personalizados le ofrecen un control total sobre la procedencia de sus plantillas Latte, lo que permite la integración con diversos sistemas de almacenamiento y flujos de trabajo.