Las macros en Twig son una herramienta poderosa que permite a los desarrolladores de Symfony crear código reutilizable en sus plantillas. En este artículo, exploraremos técnicas avanzadas para aprovechar al máximo las macros en Twig, mejorando la eficiencia y mantenibilidad de nuestras vistas.
Fundamentos de las macros
Las macros en Twig funcionan de manera similar a las funciones en lenguajes de programación. Permiten definir fragmentos de código reutilizables que pueden aceptar parámetros y devolver contenido HTML.
{# forms.html.twig #}
{% macro input(name, value, type = "text", size = 20) %}
<input type="{{ type }}" name="{{ name }}" value="{{ value|e }}" size="{{ size }}" />
{% endmacro %}
En este ejemplo, definimos una macro llamada input que genera un elemento de entrada HTML. Acepta parámetros como el nombre, valor, tipo y tamaño del input, con valores predeterminados para algunos de ellos.
Para usar esta macro:
{% import "forms.html.twig" as forms %}
{{ forms.input('username') }}
Aquí, importamos el archivo que contiene la macro y la llamamos como si fuera una función.
Macros con bloques anidados
Las macros pueden ser más flexibles al incluir bloques dentro de ellas. Esto permite personalizar partes específicas de la macro cuando se la llama.
{# forms.html.twig #}
{% macro wrapped_input(name, value, type = "text") %}
<div class="form-group">
<label for="{{ name }}">{% block label %}{{ name|capitalize }}{% endblock %}</label>
<input type="{{ type }}" name="{{ name }}" value="{{ value|e }}" id="{{ name }}" />
</div>
{% endmacro %}
Esta macro crea un input envuelto en un div y con una etiqueta. El bloque label permite personalizar el contenido de la etiqueta.
Uso avanzado:
{% import "forms.html.twig" as forms %}
{% from _self import wrapped_input %}
{{ wrapped_input('email', user.email, 'email') }}
{{ wrapped_input('password', '', 'password') }}
{% block label %}Contraseña Segura{% endblock %}
{{ endwrapped_input }}
En este ejemplo, usamos la macro de forma estándar para el campo de email, pero personalizamos la etiqueta para el campo de contraseña.
Macros con contexto
Pasar el contexto completo a una macro permite una mayor flexibilidad y la capacidad de manejar un número variable de atributos.
{# forms.html.twig #}
{% macro complex_input(_context) %}
<input type="{{ _context.type|default('text') }}"
name="{{ _context.name }}"
value="{{ _context.value|default('')|e }}"
{% for attr, value in _context.attributes|default({}) %}
{{ attr }}="{{ value }}"
{% endfor %}
/>
{% endmacro %}
Esta macro acepta un objeto de contexto que puede contener cualquier número de atributos para el input.
Uso:
{% import "forms.html.twig" as forms %}
{{ forms.complex_input({
type: 'email',
name: 'user_email',
value: user.email,
attributes: {
class: 'form-control',
placeholder: 'Ingrese su email'
}
}) }}
Aquí, pasamos un objeto completo a la macro, lo que nos permite incluir atributos adicionales de forma dinámica.
Macros recursivas
Las macros recursivas son útiles para manejar estructuras de datos anidadas, como menús multinivel.
{% macro render_menu(menu_items) %}
<ul>
{% for item in menu_items %}
<li>
<a href="{{ item.url }}">{{ item.label }}</a>
{% if item.children is defined and item.children|length > 0 %}
{{ _self.render_menu(item.children) }}
{% endif %}
</li>
{% endfor %}
</ul>
{% endmacro %}
Esta macro se llama a sí misma para renderizar submenús, creando una estructura de menú anidada.
Macros como decoradores
Las macros pueden implementar un patrón decorador, permitiéndonos envolver contenido dinámico en una estructura predefinida.
{# decorators.html.twig #}
{% macro panel(title, content) %}
<div class="panel">
<div class="panel-header">{{ title }}</div>
<div class="panel-body">{{ content|raw }}</div>
</div>
{% endmacro %}
Esta macro crea un panel con un título y contenido.
Uso:
{% import "decorators.html.twig" as decorators %}
{{ decorators.panel('Usuarios', block('user_list')) }}
{% block user_list %}
<ul>
{% for user in users %}
<li>{{ user.name }}</li>
{% endfor %}
</ul>
{% endblock %}
Aquí, usamos la macro para envolver un bloque de contenido en una estructura de panel.
Macros con herencia
Aunque Twig no soporta herencia directa de macros, podemos simularla llamando a macros base dentro de macros extendidas.
{# base_macros.html.twig #}
{% macro base_input(name, value, type = "text") %}
<input type="{{ type }}" name="{{ name }}" value="{{ value|e }}" />
{% endmacro %}
{# extended_macros.html.twig #}
{% import "base_macros.html.twig" as base %}
{% macro extended_input(name, value, type = "text") %}
<div class="form-group">
{{ base.base_input(name, value, type) }}
</div>
{% endmacro %}
Esta técnica nos permite construir sobre macros existentes, añadiendo funcionalidad adicional.
Macros como funciones de ayuda
Las macros pueden actuar como funciones de ayuda para realizar tareas comunes de formato o manipulación de datos.
{% macro format_date(date, format = 'Y-m-d') %}
{{ date|date(format) }}
{% endmacro %}
{% macro truncate(text, length = 100, suffix = '...') %}
{{ text|length > length ? text|slice(0, length) ~ suffix : text }}
{% endmacro %}
Estas macros proporcionan funcionalidad para formatear fechas y truncar texto, respectivamente.
Integración con symfony forms
Las macros son excelentes para personalizar la renderización de formularios Symfony, permitiéndonos definir estilos consistentes para los elementos del formulario.
{# form_macros.html.twig #}
{% macro form_row(form) %}
<div class="form-row">
{{ form_label(form) }}
{{ form_widget(form, {'attr': {'class': 'custom-input'}}) }}
{{ form_errors(form) }}
</div>
{% endmacro %}
Esta macro crea una fila de formulario personalizada con etiqueta, widget y errores.
Uso en una plantilla de formulario:
{% import "form_macros.html" as form_macros %}
{{ form_start(form) }}
{{ form_macros.form_row(form.name) }}
{{ form_macros.form_row(form.email) }}
{{ form_row(form.submit) }}
{{ form_end(form) }}
Aquí, usamos nuestra macro personalizada para renderizar filas de formulario específicas, mientras seguimos usando las funciones de formulario de Symfony para otras partes.
Optimización de rendimiento
Para optimizar el rendimiento al usar macros:
Depuración de Macros
La depuración de macros puede ser desafiante. Una técnica útil es usar la función dump() dentro de las macros para inspeccionar variables.
{% macro debug_input(name, value, type = "text") %}
{{ dump(name, value, type) }}
<input type="{{ type }}" name="{{ name }}" value="{{ value|e }}" />
{% endmacro %}
Esta macro mostrará los valores de sus parámetros antes de renderizar el input, lo cual es útil para depuración.
Las macros en Twig son una herramienta versátil y poderosa que pueden mejorar significativamente la estructura y mantenibilidad de tus plantillas. Es importante usar las macros con moderación para promover la reutilización y la claridad en tu código, pero sin abusar de ellas hasta el punto de que las plantillas se vuelvan difíciles de entender o mantener.