View
14.240
Download
11
Category
Preview:
DESCRIPTION
Buenas prácticas, trucos, snipets y buenos usos del sistema de plantillas Twig, tanto dentro de Symfony2 como en proyectos PHP independientes
Citation preview
Javier Eguiluz
Twig avanzado
Jornadas Symfony2 Galicia25-26 noviembre 2011 #sf2Vigo
TWIG
PHP
{{ usuario.nombre }}
<?php echo htmlspecialchars($usuario-> getNombre(), ENT_QUOTES, 'UTF-8'); ?>
1. $usuario["nombre"]2. $usuario->nombre3. $usuario->nombre()4. $usuario->getNombre()5. $usuario->isNombre()6. null
{{ usuario.nombre }}
<?php
abstract class Twig_Template implements Twig_TemplateInterface{
// ...
protected function getAttribute( $object, $item, array $arguments = array(), $type = Twig_TemplateInterface::ANY_CALL, $isDefinedTest = false) { // ... }}
Template.php
<html> <head> ... </head>
<body>
<h1>
{% block titulo %}{% endblock %}
</h1>
{% block contenidos %}{% endblock %}
{% block lateral %}{% endblock %}
</body></html>
layout.twig
<html> <head> ... </head>
<body>
<h1>
PORTADA
</h1>
<div id="contenidos">...</div>
<div id="lateral">...</div>
</body></html>
portada.twig
<html> <head> ... </head>
<body>
<h1>
PORTADA
</h1>
<div id="contenidos">...</div>
<div id="lateral">...</div>
</body></html>
portada.twig
{% extends "layout.twig" %}
PORTADA
<div id="contenidos">...</div>
<div id="lateral">...</div>
portada.twig
portada.twig{% extends "layout.twig" %}
{% block titulo %} PORTADA{% endblock %} {% block contenidos %} <div id="contenidos">...</div>{% endblock %}
{% block lateral %} <div id="lateral">...</div>{% endblock %}
contacto.twig{% extends "layout.twig" %}
{% block titulo %} CONTACTO{% endblock %} {% block contenidos %} <form>...</form>{% endblock %}
{% block lateral %} <p>...</p>{% endblock %}
Javier Eguiluz
DESARROLLOWEB ÁGIL CON
SYMFONY2
todos los ejemplos que se muestran
a continuación pertenecen al libro
Desarrollo web ágilcon Symfony2(disponible próximamente)
Precio {{ oferta.precio * iva[0] }}
Coste de envío a {{ usuario.cp | default(cp) }}
<footer> © 'now'|date('Y') - v.{{ version }}</footer>
# app/config/config.ymltwig: # ... globals: 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> © 'now'|date('Y') - v.{{ global.version }}</footer>
# app/config/config.ymltwig: # ... globals: global: cp: 01001 iva: [1.04, 1.08, 1.18] version: 1.0.3
namespace Cupon\OfertaBundle\Util;
class Util{ static public function getSlug($cadena) { // ... return $slug; }}
servicios como variables globales
# app/config/config.yml
services:
twig.extension.debug:
class: Twig_Extensions_Extension_Debug
tags:
- { name: twig.extension }
{% for articulo in articulos %}
{{ articulo.titulo }}
{# ... #}
{% else %}
No hay artículos
{% 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 %}
{% 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 perfil %} Nombre: {{ usuario.nombre }} Apellidos: {{ usuario.apellidos }} Edad: {{ usuario.edad }} años Página: {{ usuario.url }}
{% endset %}
{{ perfil }}
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 %}
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 %}
class DefaultController extends Controller{ {% if comentarios -%} /** * Comentario */ {%- else -%} /** * @Anotacion(...) */ {%- endif %}
{# formulario.html.twig #}
{% macro campo(nombre, tipo, valor) %}
<input type="{{ tipo }}"
name="{{ nombre }}"
value="{{ valor }}" />
{% endmacro %}
{% 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>
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);}
エラーが発生
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);
// ...}
{% include 'MiBundle:Carpeta:plantilla.html.twig' %}
MiBundle/
Resources/
views/
src/MiAplicacion/
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'views/Carpeta/plantilla.html.twig' %}
# 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: Symfony\Bundle\TwigBundle
\Controller\ExceptionController::showAction
modificar campos de una plantilla
{% block url_widget %}{% spaceless %} {% set type = type|default('url') %} {{ block('field_widget') }}{% endspaceless %}{% endblock url_widget %}
{{ form_row(noticia.url) }}
Label
{{ 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) }}
# app/config/config.yml
twig:
# ...
form:
resources: - 'form_div_layout.html.twig'
modificar todos los formularios
{% 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 %}
{{ form_label(fecha) }}
{{ form_errors(fecha) }}
{{ form_widget(fecha.year) }}
{{ form_widget(fecha.month) }}
{{ form_widget(fecha.day) }}
public function indexAction()
{
$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 %}
}
Symfony2
/* 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 { /* ... */ }
easybook3
{% block NamespaceDeclaration %}{% if namespace %}namespace {{ namespace }};
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 %}}
Doctrine2ActiveRecord
<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>
<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>
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( )
strlen( )
{% 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 ... }}
{% 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( )
strpos( )
{% 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 %}
{% set bundles = {
'AsseticBundle' => '.../vendor/...',
'BackendBundle' => '.../src/...',
'CiudadBundle' => '.../src/...',
'DoctrineBundle' => '.../vendor/...',
...
} %}
{% for name in bundles|keys|sort %}
<tr>
<th>{{ name }}</th>
<td>{{ bundles[name] }}</td>
</tr>
{% endfor %}
{% 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 }}
emailresultado
{% set usuarios = [
{ 'email': '..@..', 'contacto': 'email' },
{ 'movil': '9....', 'contacto': 'movil' }
] %}
{% set usuarios = [
{ 'email': '..@..', 'contacto': 'email' },
{ 'movil': '9....', 'contacto': 'movil' }
] %}
{{ usuario[contacto] }}
ERRORresultado
{% 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) }}
{% extends usuario.tipo ~ '.html.twig' %}
{# usuario = {'tipo': 'admin'} #}admin.html.twig
{# usuario = {'tipo': 'usuario'} #}usuario.html.twig
{% extends [
'categoria_' ~ noticia.categoria ~ '.html.twig',
'seccion_' ~ noticia.seccion ~ '.html.twig',
'noticia.html.twig'
] %}
{% include [
'lateral_' ~ noticia.categoria ~ '.html.twig',
'lateral_' ~ noticia.seccion ~ '.html.twig',
'lateral.html.twig'
] %}
{% include '...' ignore missing %}
{% include '...' ignore missing
with { ... } %}
{% include '...' ignore missing
with { ... } only %}
Recommended