Twig avanzado
Javier Eguiluz


     Jornadas Symfony2 Galicia
     25-26 noviembre 2011        #sf2Vigo
me presento
 •   Javier Eguiluz
 •   formador en Symfony2 y
     nuevas tecnologías
creador de http://symfony.es
apasionado de Symfony
           http://connect.sensiolabs.com/
                 profile/javier.eguiluz
objetivos de la sesión
 •   Buenas prácticas
 •   Trucos
 •   Usos avanzados
 •   Snipets
Si no sabes Twig, te vas a
   perder a partir de la
 siguiente transparencia
Aprende Twig
en 5 minutos
«Twig es un lenguaje y
motor de plantillas PHP»
twig se puede usar en




               Cualquier
Symfony2     proyecto PHP
¿Por qué usar
       Twig?
$usuario

public function getNombre()
{
  return $this->nombre;
}
TWIG




{{ usuario.nombre }}
PHP




echo $usuario->getNombre()
PHP




<?php
echo $usuario->getNombre();
?>
PHP

<?php
echo htmlspecialchars(
   $usuario->getNombre(),
   ENT_QUOTES,
   'UTF-8');
?>
TWIG


    {{ usuario.nombre }}

                                   PHP

<?php echo htmlspecialchars($usuario->
getNombre(), ENT_QUOTES, 'UTF-8'); ?>
Mostrar
información
{# ... #}
{% ... %}
{{ ... }}
<p> Hola {{ usuario }}
Tienes {{ edad }} años y
vives en {{ ciudad }} </p>
<p> Hola {{ usuario.nombre }}
Tienes {{ usuario.edad }}
años y vives en
{{ usuario.ciudad }} </p>
{{ usuario.nombre }}
{{ usuario.nombre }}
1.   $usuario["nombre"]
2.   $usuario->nombre
3.   $usuario->nombre()
4.   $usuario->getNombre()
5.   $usuario->isNombre()
6.   null
<?php             Template.php
abstract class   Twig_Template   implements
                                 Twig_TemplateInterface
{

    // ...

    protected function getAttribute(
        $object,
        $item,
        array $arguments = array(),
        $type = Twig_TemplateInterface::ANY_CALL,
        $isDefinedTest = false) {

        // ...
twig-ext

Derick Rethans
http://github.com/derickr/twig-ext
Modificar
información
{{ descripcion }}
{{ descripcion | striptags }}
{{ titular | striptags | upper }}
<strong>Lorem ipsum</strong>
dolor sit <em>amet</em>
{{ biografia }}
&lt;strong&gt;Lorem
ipsum&lt;/strong&gt; dolor
sit &lt;em&gt;amet&lt;/em&gt;
{{ biografia | raw }}
Espacios
en blanco
<ul>
  <li>
     <a ... >XXX</a>
  </li>

  <li>
     ...
{% spaceless %}
{% spaceless %}
<ul>
  <li>
     <a ... >XXX</a>
  </li>

  <li>
     ...
{% endspaceless %}
<ul><li><a ... >XXX</a></li><li>...
Estructuras
 de control
{% for elemento in coleccion %}

   {# ... #}

{% endfor %}
{% for clave, elemento
   in coleccion %}

   {# ... #}

{% endfor %}
{% if condicion1 %}
  {# ... #}
{% elseif condicion2 %}
  {# ... #}
{% else %}
  {# ... #}
{% endif %}
Herencia
de plantillas
PORTADA
CONTACTO
# TITULO #




                    # LATERAL #
   # CONTENIDOS #
# TITULO #          layout.twig




                         # LATERAL #
   # CONTENIDOS #
<html> <head> ... </head>    layout.twig
<body>
    <h1>
       {% block titulo %}{% endblock %}
    </h1>

    {% block contenidos %}{% endblock %}
    {% block lateral %}{% endblock %}
</body></html>
<html> <head> ... </head>   portada.twig
<body>
    <h1>
       PORTADA
    </h1>

    <div id="contenidos">...</div>
    <div id="lateral">...</div>
</body></html>
<html> <head> ... </head>   portada.twig
<body>
    <h1>
       PORTADA
    </h1>

    <div id="contenidos">...</div>
    <div id="lateral">...</div>
</body></html>
portada.twig


  PORTADA



<div id="contenidos">...</div>
<div id="lateral">...</div>
portada.twig
{% extends "layout.twig"   %}


     PORTADA



   <div id="contenidos">...</div>
   <div id="lateral">...</div>
{% extends "layout.twig" %} portada.twig

{% block titulo %}
  PORTADA
{% endblock %}

{% block contenidos %}
  <div id="contenidos">...</div>
{% endblock %}

{% block lateral %}
  <div id="lateral">...</div>
{% endblock %}
{% extends "layout.twig" %}
                          contacto.twig
{% block titulo %}
  CONTACTO
{% endblock %}

{% block contenidos %}
  <form>...</form>
{% endblock %}

{% block lateral %}
  <p>...</p>
{% endblock %}
ya pasaron los
5 minutos
DESARROLLO
WEB ÁGIL CON        todos los ejemplos que se muestran
SYMFONY2             a continuación pertenecen al libro

                    Desarrollo web ágil
                      con Symfony2
                        (disponible próximamente)

   Javier Eguiluz
variables
 globales
# app/config/config.yml
twig:
    # ...
    globals:
        cp:       01001
        iva:      [1.04, 1.08, 1.18]
        version: 1.0.3
# app/config/config.yml
twig:
    # ...
    globals:
        cp:       01001
        iva:      [1.04, 1.08, 1.18]
        version: 1.0.3



Precio {{ oferta.precio * iva[0] }}


Coste de envío a {{ usuario.cp | default(cp) }}


<footer>
    &copy; 'now'|date('Y') - v.{{ version }}
</footer>
# app/config/config.yml
twig:
    # ...
    globals:
        global:
             cp:      01001
             iva:     [1.04, 1.08, 1.18]
             version: 1.0.3
# app/config/config.yml
twig:
    # ...
    globals:
        global:
             cp:      01001
             iva:     [1.04, 1.08, 1.18]
             version: 1.0.3



Precio {{ oferta.precio * global.iva[0] }}


Coste de envío a {{ oferta.cp | default(global.cp) }}


<footer>
    &copy; 'now'|date('Y') - v.{{ global.version }}
</footer>
servicios como variables globales
namespace CuponOfertaBundleUtil;

class Util
{
  static public function getSlug($cadena)
  {
    // ...
    return $slug;
  }
}
# app/config/config.yml
services:
  # ...
  cupon.utilidades:
    class: CuponOfertaBundleUtilUtil
# app/config/config.yml
twig:
    # ...
    globals:
        utilidades: @cupon.utilidades
# app/config/config.yml
twig:
    # ...
    globals:
        utilidades: @cupon.utilidades
{{ utilidades.getSlug('Lorem ipsum
dolor sit amet') }}
depurando
 variables
<?php var_dump($oferta); ?>


{% debug oferta %}
# app/config/config.yml
services:
    twig.extension.debug:
        class: Twig_Extensions_Extension_Debug
        tags:
            - { name: twig.extension }
for ... else
{% for articulo in articulos %}
  {{ articulo.titulo }}
  {# ... #}
{% endfor %}
{% for articulo in articulos %}
  {{ articulo.titulo }}
  {# ... #}
{% else %}
  No hay artículos
{% endfor %}
for ... if
Itera sólamente por las
     ofertas baratas
{% for oferta in ofertas
   if oferta.precio < 10 %}

  {# ... #}

{% endfor %}
1.2


{% for elemento in coleccion
   if condicion %}

  {# ... #}

{% endfor %}
Itera sólamente por los
     amigos del usuario
{% set usuarios = 1..30 %}
{% set amigos = [12, 29, 34, 55, 67] %}
{% set usuarios = 1..30 %}
{% set amigos = [12, 29, 34, 55, 67] %}

{% for usuario in usuarios
    if usuario in amigos %}

     {# sólo 12 y 29 #}

{% endfor %}
Operadores
de división
operación      resultado
{{ 12 / 7 }}    1.7142857142

{{ 12 // 7 }}        1

{{ 12 % 7 }}         5
creando
variables
{% set nombre = 'José García' %}

{% set edad = 27 %}
{% set precio = 104.83 %}

{% set conectado = false %}

{% set tasaImpuestos = [4, 8, 18] %}
{% set perfil =    {
     'nombre':     'José García',
     'perfiles':   ['usuario', 'admin'],
     'edad':       27,
     'validado':   true
} %}
{% set nombreCompleto = nombre ~ ' ' ~
                        apellidos %}


{% set experiencia = edad ~ ' años' %}
{% set perfil %}
 Nombre: {{ usuario.nombre }}
 Apellidos: {{ usuario.apellidos }}
 Edad: {{ usuario.edad }} años
 Página: {{ usuario.url }}
{% endset %}

{{ perfil }}
{% set nombre, edad, activado =
   'José', 27, false %}


{{ nombre }}
{{ edad }}
{% if activado %}
espacios
en blanco
class DefaultController extends Controller
{
    {% if comentarios %}
    /**
     * Primera línea
     * Segunda línea
     */
    {% endif %}
NO


class DefaultController extends Controller
{
    /**
     * Primera línea
     * Segunda línea
     */
SI


class DefaultController extends Controller
{
        /**
     * Primera línea
     * Segunda línea
     */
SI


class DefaultController extends Controller
{
        /**
     * Primera línea
     * Segunda línea
     */
class DefaultController extends Controller
{
    {% if comentarios %}
    /**
     * Primera línea
     * Segunda línea
     */
    {% endif %}
class DefaultController extends Controller
{
    {% if comentarios %}
    /**
     * Primera línea
     * Segunda línea
     */
    {% endif %}
class DefaultController extends Controller
{
{% if comentarios %}
    /**
     * Primera línea
     * Segunda línea
     */
{% endif %}
SI


class DefaultController extends Controller
{
    /**
     * Primera línea
     * Segunda línea
     */
class DefaultController extends Controller
{
    {% if comentarios %}
    /**
     * Primera línea
     * Segunda línea
     */
    {% endif %}
class DefaultController extends Controller
{
    {% if comentarios -%}
    /**
     * Primera línea
     * Segunda línea
     */
    {%- endif %}
SI


class DefaultController extends Controller
{
    /**
     * Primera línea
     * Segunda línea
     */
{% if condicion -%}

  {# ... #}

{%- endif %}
class DefaultController extends Controller
{
    {% if comentarios -%}
    /**
     * Comentario
     */
    {%- else -%}
    /**
     * @Anotacion(...)
     */
    {%- endif %}
formatear
información
{{ '%.0f'|format(time * 1000) }} ms
{{ '%.0f'|format(time * 1000) }} ms
{{ '%.0f'|format(time * 1000) }} ms
{{ '%.0f'|format(time * 1000) }} ms




{{ '%0.2f'|format(time * 1000) }} ms
macros
polimórficas
{# formulario.html.twig #}
{% macro campo(nombre, tipo, valor) %}
    <input type="{{ tipo }}"
           name="{{ nombre }}"
           value="{{ valor }}" />
{% endmacro %}
{% from 'formularios.html.twig'
   import campo as campo %}
{% from 'formularios.html.twig'
   import campo as campo %}

<table>
    {{ campo('nombre', 'text', 'José') }}
    {{ campo('apellidos', 'text', 'García Pérez') }}
    {{ campo('telefono', 'text') }}
</table>
{% from 'formularios.html.twig'
   import campo as campo %}

<table>
    {{ campo('nombre', 'text', 'José') }}
    {{ campo('apellidos', 'text', 'García Pérez') }}
    {{ campo('telefono', 'text') }}
</table>

<ul>
    {{ campo('nombre', 'text', 'José') }}
    {{ campo('apellidos', 'text', 'García Pérez') }}
    {{ campo('telefono', 'text') }}
</ul>
{# formulario.html.twig #}
{% macro campo(nombre, tipo, valor) %}
    <input type="{{ tipo }}" name="{{ nombre }}"
           value="{{ valor }}" />
{% endmacro %}
{# formulario.html.twig #}
{% macro campo(nombre, tipo, valor) %}
    <input type="{{ tipo }}" name="{{ nombre }}"
           value="{{ valor }}" />
{% endmacro %}



{% macro fila(nombre, tipo, valor) %}
  <tr>
    <td>{{ nombre | capitalize }}</td>
    <td>{{ _self.campo(nombre, tipo, valor) }}</td>
  </tr>
{% endmacro %}
{# formulario.html.twig #}
{% macro campo(nombre, tipo, valor) %}
    <input type="{{ tipo }}" name="{{ nombre }}"
           value="{{ valor }}" />
{% endmacro %}
{# formulario.html.twig #}
{% macro campo(nombre, tipo, valor) %}
    <input type="{{ tipo }}" name="{{ nombre }}"
           value="{{ valor }}" />
{% endmacro %}



{% macro item(nombre, tipo, valor) %}
  <li>
    {{ _self.campo(nombre, tipo, valor) }}
  </li>
{% endmacro %}
{% from 'formularios.html.twig'
   import campo as campo %}



    {{ campo('nombre', 'text', 'José') }}
    {{ campo('apellidos', 'text', 'García Pérez') }}
    {{ campo('telefono', 'text') }}
{% from 'formularios.html.twig'
   import fila as campo %}

<table>
    {{ campo('nombre', 'text', 'José') }}
    {{ campo('apellidos', 'text', 'García Pérez') }}
    {{ campo('telefono', 'text') }}
</table>
{% from 'formularios.html.twig'
   import item as campo %}

<ul>
    {{ campo('nombre', 'text', 'José') }}
    {{ campo('apellidos', 'text', 'García Pérez') }}
    {{ campo('telefono', 'text') }}
</ul>
filtros dependientes
         del entorno
public function getFilters()
{
  return array('longitud' => new
     Twig_Filter_Method($this,
                         'longitud')
  );
}

function longitud($valor)
{
    return strlen($valor);
}
public function getFilters()
{
  return array('longitud' => new
     Twig_Filter_Method($this,
                         'longitud')
  );
}

function longitud($valor)
{
    return strlen($valor);
}
function longitud($valor)
{
   return mb_strlen($valor, 'EUC-JP');
}
public function getFilters()
{
    return array(
        'longitud' => new Twig_Filter_Method(
            $this,
            'longitud',
            array('needs_environment' => true)
        )
    );
}
public function getFilters()
{
    return array(
        'longitud' => new Twig_Filter_Method(
            $this,
            'longitud',
            array('needs_environment' => true)
        )
    );
}
function longitud(Twig_Environment $entorno, $valor)
{
    $codificacion = $entorno->getCharset();
    return mb_strlen($valor, $codificacion);
}
class Twig_Environment
{
    const VERSION = '1.1.2';
    // ...
    $options = array_merge(array(
        'debug'               => false,
        'charset'             => 'UTF-8',
        'base_template_class' => 'Twig_Template',
        'strict_variables'    => false,
        'autoescape'          => true,
        'cache'               => false,
        'auto_reload'         => null,
        'optimizations'       => -1,
    ), $options);
    // ...
}
notación
 bundle
{% include
'MiBundle:Carpeta:plantilla.html.twig' %}
{% include
'MiBundle:Carpeta:plantilla.html.twig' %}

      src/MiAplicacion/
          MiBundle/
              Resources/
                   views/
                       Carpeta/
                       plantilla.html.twig
{% include
'MiBundle:Carpeta:plantilla.html.twig' %}
{% include
'MiBundle:Carpeta:plantilla.html.twig' %}


{% include 'MiBundle:Carpeta:Subcarpeta/
            plantilla.html.twig' %}
{% include
'MiBundle:Carpeta:plantilla.html.twig' %}


{% include 'MiBundle:Carpeta:Subcarpeta/
            plantilla.html.twig' %}


{% include 'MiBundle:Carpeta:Subcarpeta1/
   Subcarpeta2/plantilla.html.twig' %}
{% include
'MiBundle:Carpeta:plantilla.html.twig' %}
{% include
'MiBundle:Carpeta:plantilla.html.twig' %}


{% include
'MiBundle::Carpeta/plantilla.html.twig' %}
{% include
'MiBundle:Carpeta:plantilla.html.twig' %}
{% include
'MiBundle:Carpeta:plantilla.html.twig' %}


{% include
'views/Carpeta/plantilla.html.twig' %}
opciones de
configuración
# app/config/config.yml
twig:
    autoescape:           true
    auto_reload:          ~
    cache:                %kernel.cache_dir%/twig
    charset:              %kernel.charset%
    debug:                %kernel.debug%
    strict_variables:     ~
$twig = new Twig_Environment($loader, array(
    'debug'    => true,
    'strict_variables' => true,
    'charset' => 'UTF-8',
    'cache'    => __DIR__.'/cache'
));
# app/config/config.yml
 twig:
     base_template_class:   Twig_Template


<?php

class __TwigTemplate_82262eae3f96052ef64432a9ddc53915
      extends Twig_Template
{
    protected $parent;

    public function __construct(Twig_Environment $env)
    {
        // ...
    }
# app/config/config.yml
 twig:
     base_template_class:   Twig_Template


<?php

class __TwigTemplate_82262eae3f96052ef64432a9ddc53915
      extends Twig_Template
{
    protected $parent;

    public function __construct(Twig_Environment $env)
    {
        // ...
    }
# app/config/config.yml
twig:
    # ...
    exception_controller: SymfonyBundleTwigBundle
ControllerExceptionController::showAction
# app/config/config.yml
twig:
    # ...
    form:
        resources: [ ... ]
formularios
personalizados
modificar campos de una plantilla
{{ form_row(noticia.url) }}
modificar campos de una plantilla
{{ form_row(noticia.url) }}

Label
modificar campos de una plantilla
{{ form_row(noticia.url) }}

Label
{% block url_widget %}
{% spaceless %}
    {% set type = type|default('url') %}
    {{ block('field_widget') }}
{% endspaceless %}
{% endblock url_widget %}
{{ form_row(noticia.url) }}


{% form_theme form _self %}

{% block url_widget %}
 {% set type = 'url' %}
 <em>http://</em> {{ block('field_widget') }}
{% endblock url_widget %}
{{ form_row(noticia.url) }}


{% form_theme form _self %}

{% block url_widget %}
 {% set type = 'url' %}
 <em>http://</em> {{ block('field_widget') }}
{% endblock url_widget %}
{{ form_row(noticia.url) }}


{% form_theme form _self %}

{% block url_widget %}
 {% set type = 'url' %}
 <em>http://</em> {{ block('field_widget') }}
{% endblock url_widget %}

Label http://
modificar campos de varias plantillas

{# src/.../Resources/views/Form/form.html.twig #}

{% block url_widget %}
   {% set type = 'url' %}
   <em>http://</em> {{ block('field_widget') }}
{% endblock url_widget %}
{% form_theme form
   'MiBundle:Form:form.html.twig' %}


{{ form_row(noticia.titular) }}

{{ form_row(noticia.publicada) }}

{{ form_row(noticia.url) }}
modificar todos los formularios
# app/config/config.yml
twig:
  # ...
  form:
    resources:
      - 'form_div_layout.html.twig'
# app/config/config.yml
twig:
  # ...
  form:
    resources:
      - 'form_table_layout.html.twig'
{% use "form_div_layout.html.twig" %}
{% block field_row %}
{% spaceless %}
  <tr>
    <td>
       {{ form_label(form, label|default(null)) }}
    </td>
    <td>
       {{ form_errors(form) }}
       {{ form_widget(form) }}
    </td>
  </tr>
{% endspaceless %}
{% endblock field_row %}

{# ... #}
{% use "form_div_layout.html.twig" %}
{% block field_row %}
    {# ... #}
{% endblock %}

{% block form_errors %}
    {# ... #}
{% endblock %}

{% block hidden_row %}
    {# ... #}
{% endblock %}

{% block form_widget %}
    {# ... #}
{% endblock %}
# app/config/config.yml
twig:
  # ...
  form:
    resources:
      - 'MiBundle:Form:form.html.twig'
mostrando
campos de fecha
{{ form_row(fecha) }}
{{ form_label(fecha) }}
{{ form_errors(fecha) }}

{{ form_widget(fecha) }}
{{ form_label(fecha) }}
{{ form_errors(fecha) }}

{{ form_widget(fecha.year) }}
{{ form_widget(fecha.month) }}
{{ form_widget(fecha.day) }}
generando
   código
«Twig genera con
facilidad cualquier tipo
     de contenido»
public function indexAction()                     Symfony2
{
  $em = $this->getDoctrine()->getEntityManager();

  $entities = $em->getRepository('{{ bundle }}:{{ entity }}')
                 ->findAll();

{% if 'annotation' == format %}
  return array('entities' => $entities);
{% else %}
  return $this->render('{{ bundle }}:
    {{ entity|replace({'': '/'}) }}:index.html.twig',
    array('entities' => $entities));
{% endif %}
}
easybook3
/* page size, margins, headers & footers
--------------------------------------------- */
@page {
    size: {{ edition.page_size }};
}

{% if edition.two_sided %}
@page:right {
    margin: {{ edition.margin.top|default('25mm') }}
{{ edition.margin.outter|default('20mm') }}
{{ edition.margin.bottom|default('25mm') }}
{{ edition.margin.inner|default('30mm') }};

    @top-left {
        /* ... */
    }
{% block NamespaceDeclaration %}
{% if namespace %}                                      Doctrine2
namespace {{ namespace }};                           ActiveRecord
use {{ namespace }}Base{{ classname }} as Base{{ classname }};
{% else %}
use Base{{ classname }} as Base{{ classname }};
{% endif %}
{% endblock %}

{% block DocBlock %}
/**
 * ActiveRecord class.
 */
{% endblock %}

{% block ClassDeclaration %}
class {{ classname }} extends Base{{ classname }}
{% endblock %}
{
{% block Body %}
    // add your code here
{% endblock %}
}
https://github.com/
cedriclombardot/
TwigGenerator
twig.js
<select id="ciudad">
    {% for ciudad in ciudades %}
    <option value="{{ ciudad.slug }}">
        {{ ciudad.nombre }}
    </option>
    {% endfor %}
</select>
<script type="text/javascript">
  var lista = document.getElementById('ciudad');
  var ciudad = lista.options[lista.selectedIndex].value;

  lista.onchange = function() {
    var url = {{ path('portada', {'ciudad': ciudad }) }};
    window.location = url;
  };
</script>
<script type="text/javascript">
  var lista = document.getElementById('ciudad');
  var ciudad = lista.options[lista.selectedIndex].value;

  lista.onchange = function() {
    var url = {{ path('portada', {'ciudad': ciudad }) }};
    window.location = url;
  };
</script>
<script type="text/javascript">
  var lista = document.getElementById('ciudad');
  var ciudad = lista.options[lista.selectedIndex].value;

  lista.onchange = function() {
    var url = Routing.generate('portada',
                                {'ciudad': ciudad});
    window.location = url;
  };
</script>
<script type="text/javascript" src="
{{ asset('bundles/fosjsrouting/js/router.js') }}
"></script>

<script type="text/javascript" src="
{{ path('fos_js_routing_js', {"callback":
"fos.Router.setData"}) }}
"></script>
<script type="text/javascript">
  var lista = document.getElementById('ciudad');
  var ciudad = lista.options[lista.selectedIndex].value;

  lista.onchange = function() {
    var url = Routing.generate('portada',
                                {'ciudad': ciudad});
    window.location = url;
  };
</script>
https://github.com/
FriendsOfSymfony/
FOSJsRoutingBundle
{% twig_js name="perfil" %}
Nombre: {{ nombre }}
Apellidos: {{ apellidos }}
{% twig_js name="perfil" %}
Nombre: {{ nombre }}
Apellidos: {{ apellidos }}
<script type="text/javascript"   src="twig.js"></script>
<script type="text/javascript"   src="perfil.js"></script>

<script type="text/javascript">
  alert(Twig.render(perfil, { nombre:
        'José', apellidos: 'Pérez' }));
</script>
https://github.com/
schmittjoh/
twig.js
flexible
{{ ... | length }}



Tienes {{ amigos|length }} amigos
y tu nombre tiene
{{ nombre|length }} letras
{{ ... | length }}

                   count( )
Tienes {{ amigos|length }} amigos
y tu nombre tiene
{{ nombre|length }} letras
{{ ... | length }}

                        count( )
Tienes {{ amigos|length }} amigos
y tu nombre tiene
{{ nombre|length }} letras

            strlen( )
{{ ... in ... }}

{% if fecha in ['2005', '2006'] %}
  Eres un early-adopter
{% endif %}


{% if password in login %}
  La contraseña no puede ser
  una parte del login
{% endif %}
{{ ... in ... }}
            in_array( )
{% if fecha in ['2005', '2006'] %}
  Eres un early-adopter
{% endif %}


{% if password in login %}
  La contraseña no puede ser
  una parte del login
{% endif %}
{{ ... in ... }}
            in_array( )
{% if fecha in ['2005', '2006'] %}
  Eres un early-adopter
{% endif %}
                strpos( )
{% if password in login %}
  La contraseña no puede ser
  una parte del login
{% endif %}
{% for letra in 'a'|upper..inicial|default('z')|upper %}
    {{ letra }}
{% endfor %}
{% for letra in 'a'|upper..inicial|default('z')|upper %}
    {{ letra }}
{% endfor %}

{% filter upper %}
{% for letra in 'a'..inicial|default('z') %}
    {{ letra }}
{% endfor %}
{% endfilter %}
{% for letra in 'a'|upper..inicial|default('z')|upper %}
    {{ letra }}
{% endfor %}

{% filter upper %}
{% for letra in 'a'..inicial|default('z') %}
    {{ letra }}
{% endfor %}
{% endfilter %}

{% for letra in 'a'..inicial|default('z') %}
    {{ letra | upper }}
{% endfor %}
propiedades
   variables
{{ objeto.propiedad }}
{{ objeto.propiedad }}
{% set bundles = {
     'AsseticBundle'    =>   '.../vendor/...',
     'BackendBundle'    =>   '.../src/...',
     'CiudadBundle'     =>   '.../src/...',
     'DoctrineBundle'   =>   '.../vendor/...',
     ...
} %}
NO




{{ bundles.'AsseticBundle' }}
SI




{% set nombre = 'AsseticBundle' %}

{{ bundles[nombre] }}
{% for name in bundles|keys|sort %}
<tr>
     <th>{{ name }}</th>
     <td>{{ bundles[name] }}</td>
</tr>
{% endfor %}
{% set usuarios = [
     { 'email': '..@..' },
     { 'movil': '9....' }
] %}
{% set usuarios = [
     { 'email': '..@..' },
     { 'movil': '9....' }
] %}


{% for usuario in usuarios %}
  {{ usuario.nombre }}
  Contacto {{ usuario.????? }}
{% endfor %}
{% set usuarios = [
 { 'email': '..@..', 'contacto': 'email' },
 { 'movil': '9....', 'contacto': 'movil' }
] %}
{% set usuarios = [
 { 'email': '..@..', 'contacto': 'email' },
 { 'movil': '9....', 'contacto': 'movil' }
] %}


 {{ usuario.contacto }}


 resultado   email
{% set usuarios = [
 { 'email': '..@..', 'contacto': 'email' },
 { 'movil': '9....', 'contacto': 'movil' }
] %}
{% set usuarios = [
 { 'email': '..@..', 'contacto': 'email' },
 { 'movil': '9....', 'contacto': 'movil' }
] %}


 {{ usuario[contacto] }}


 resultado   ERROR
{% set usuarios = [
 { 'email': '..@..', 'contacto': 'email' },
 { 'movil': '9....', 'contacto': 'movil' }
] %}
{% set usuarios = [
 { 'email': '..@..', 'contacto': 'email' },
 { 'movil': '9....', 'contacto': 'movil' }
] %}


 {{ usuario[usuario.contacto] }}


 resultado   ..@..
{% set usuarios = [
 { 'email': '..@..', 'contacto': 'email' },
 { 'movil': '9....', 'contacto': 'movil' }
] %}
{% set usuarios = [
 { 'email': '..@..', 'contacto': 'email' },
 { 'movil': '9....', 'contacto': 'movil' }
] %}


 {{ attribute(usuario, usuario.contacto) }}
{% set usuarios = [
 { 'email': '..@..', 'contacto': 'email' },
 { 'movil': '9....', 'contacto': 'movil' }
] %}


 {{ attribute(usuario, usuario.contacto) }}


 resultado   ..@..
1.2

{{ attribute(objeto, propiedad) }}


{{ attribute(objeto, expresion) }}


{{ attribute(producto, 'foto' ~ i) }}
1.2

{{ attribute(objeto, metodo) }}



{{ attribute(objeto, metodo,
             argumentos) }}
herencia
dinámica
{% extends usuario.tipo ~ '.html.twig' %}


{# usuario = {'tipo': 'admin'} #}
admin.html.twig

{# usuario = {'tipo': 'usuario'} #}
usuario.html.twig
{% extends listado ?
     'listado.html.twig'
     :
     'tabla.html.twig' %}
1.2




{% extends ['primera.html.twig',
            'segunda.html.twig',
            'tercera.html.twig'] %}
{% extends 'noticia.html.twig' %}
{% extends [
'categoria_' ~ noticia.categoria ~ '.html.twig',
'seccion_' ~ noticia.seccion ~ '.html.twig',
'noticia.html.twig'
] %}
include
dinámico
1.2




{% include ['primera.html.twig',
            'segunda.html.twig',
            'tercera.html.twig'] %}
{% include [
'lateral_' ~ noticia.categoria ~ '.html.twig',
'lateral_' ~ noticia.seccion ~ '.html.twig',
'lateral.html.twig'
] %}
{% set seccion = ... %}

{% include
   'lateral_' ~ seccion ~ '.html.twig'
%}
1.2


{% set seccion = ... %}

{% include
   'lateral_' ~ seccion ~ '.html.twig'
   ignore missing
%}
{% include '...' ignore missing %}

{% include '...' ignore missing
   with { ... } %}

{% include '...' ignore missing
   with { ... } only %}
muchas
gracias
dudas
preguntas
comentarios
contacta
javier.eguiluz@gmail.com

conecta
linkedin.com/in/javiereguiluz
copyright
Los contenidos de esta
presentación son propiedad
de su autor. No se pueden
reutilizar sin el consentimiento
expreso de su autor.

Twig avanzado (sf2Vigo)