Este foro ya no está activo, así que no puedes publicar nuevas preguntas ni responder a las preguntas existentes.

Generar nuevo contenido con Twig

18 de febrero de 2015

Hola a tod@s. Te una duda con Twig. ¿Puedo crear información HTML a partir de una sola variable como se crean los formularios? Ejemplo: los formularios en Twig se generan con {{ form(form) }}. ¿Podría crear una tabla? Ejemplo: {{ table(table) }}.

¡Quedo atento!


Respuestas

#1

En Twig tienes dos formas de hacerlo:

  • Macros: si el contenido a generar se usa solamente en unas pocas plantillas.
  • Funciones: si el contenido se genera por toda la aplicación.

Macros

Consulta la documentación oficial sobre macros de Twig y verás que es tan sencillo como hacer lo siguiente:

{% macro table(parameters) %}
    <table>
        ...
    </table>
{% endmacro %}

Y en la plantilla donde quieras usar este macro, copias su contenido y haces lo siguiente:

{% import _self as html %}
 
{{ html.table(items) }}

También puedes guardar las macros en una plantilla Twig específica e importarla en todas las demás plantillas que vayan a usar esas macros.

Funciones

Consulta la documentación oficial sobre cómo crear una extensión Twig en Symfony y cómo extender Twig mediante funciones:

Primero crea una clase para definir una extensión de Twig:

// src/AppBundle/Twig/AppExtension.php
namespace AppBundle\Twig;
 
class AppExtension extends \Twig_Extension
{
    public function getFunctions()
    {
        return array(
            new \Twig_SimpleFunction('table', array($this, 'createTable'), array('is_safe' => array('html'))),
        );
    }
 
    public function createTable($parameters)
    {
        $html = '<table>';
        // ...
        $html .= '</table>';
 
        return $html;
    }
 
    public function getName()
    {
        return 'app_extension';
    }
}

Después define un servicio para que esta extensión se active en toda la aplicación:

# app/config/services.yml
services:
    app.twig_extension:
        class: AppBundle\Twig\AppExtension
        public: false
        tags:
            - { name: twig.extension }

Y ya está. Ahora ya puedes incluir lo siguiente en cualquier plantilla de la aplicación:

{{ table(items) }}

Lo único que debes tener en cuenta es que al definir la función con Twig_SimpleFunction() es muy importante que en el tercer argumento incluyas lo siguiente: array('is_safe' => array('html')). Esto le dice a Twig que tu función está generando contenido HTML y por tanto, que no debe escaparlo sino mostrarlo directamente en el navegador.

@javiereguiluz

18 febrero 2015, 8:40
#2

¡Muchas gracias buen hombre!

@cristian_angulo

18 febrero 2015, 15:03
#3

Hola. Les comparto. En ocasiones necesitamos pasarle parámetros a nuestra plantilla en la extensión que estamos creando y renderizar. Se hace de esta manera:

namespace AppBundle\Twig;
 
class AppExtension extends \Twig_Extension
{
  public function getFunctions()
  {
      return array(
          new \Twig_SimpleFunction('table',
          array($this, 'createTable'),
          array('is_safe' => array('html'),
          'needs_environment' => true
        )),
      );
  }
 
  public function createTable(\Twig_Environment $twig = null, $parameters)
  {
      return $twig->render('AppBundle::table.html.twig', array('parameters' => $parameters));
  }
 
  public function getName()
  {
      return 'app_extension';
  }
}

Donde vamos a mostrar la información llamamos nuestra extensión: {{ table('tabla') }}

Acá, información para complementar: Rendering templates from a Twig extension

@cristian_angulo

18 febrero 2015, 22:51
#4

@cristian_angulo, muchas gracias por mostrar la solución final que habéis utilizado. Efectivamente tienes razón y en este caso era mejor usar el environment de Twig para renderizar la plantilla Twig en vez de generar el código HTML a mano.

@javiereguiluz

19 febrero 2015, 8:41
#5

Buenas, para este caso específico donde tu extensión solo va a renderizar un template sin hacer nada más, puedes simplemente desde cualquier archivo .twig usar la función include:

{{ include("AppBundle::table.html.twig", { ... }) }}

Esta acotación es para que otras personas no vayan a crear extensiones solo para renderizar plantillas.

Saludos!

@manuel_j555

20 febrero 2015, 1:03