Upload
javier-eguiluz
View
10.334
Download
4
Embed Size (px)
Citation preview
Twig, los mejores trucos y técnicas avanzadasJavier Eguíluz
Universitat Jaume I · Castellón · 15-16 junio 2012 · desymfony.com
PATROCINADOR PLATINO
PATROCINADORES ORO
PATROCINADORES PLATA
PATROCINADORES BRONCE
¡muchas gracias a nuestros patrocinadores!
Agenda
• Buenas prácticas
• Técnicas avanzadas
• Trucos y cosas nuevas
CódigoEl código fuente de los ejemplos más avanzados de esta ponencia está disponible en:
https://github.com/javiereguiluz/desymfony!twig
AVANZADOINTERMEDIOBÁSICO1.*
PERSONALIZACIÓN EXTREMA DE
FORMULARIOS
<div> {{ form_label(form.nombre) }} {{ form_errors(form.nombre) }} {{ form_widget(form.nombre) }}</div>
{% extends '::base.html.twig' %}{% form_theme form _self %}
{% block integer_widget %} <div class="integer_widget"> {% set type = type|default('number') %} {{ block('field_widget') }} </div>{% endblock %}
{% block content %} {# render the form #} {{ form_row(form.age) }}{% endblock %}
{% extends '::base.html.twig' %}{% form_theme form _self %}
{% block integer_widget %} <div class="integer_widget"> {% set type = type|default('number') %} {{ block('field_widget') }} </div>{% endblock %}
{% block content %} {# render the form #} {{ form_row(form.age) }}{% endblock %}
{% extends '::base.html.twig' %}{% form_theme form _self %}
{% block integer_widget %} <div class="integer_widget"> {% set type = type|default('number') %} {{ block('field_widget') }} </div>{% endblock %}
{% block content %} {# render the form #} {{ form_row(form.age) }}{% endblock %}
{% form_theme form _self %}
{% block _formulario_nombre_widget %} <div class="especial"><strong> {{ block('field_widget') }} </strong></div>{% endblock %}
{{ form_widget(form.nombre) }}
{% form_theme form _self %}
{% block _formulario_nombre_widget %} <div class="especial"><strong> {{ block('field_widget') }} </strong></div>{% endblock %}
{{ form_widget(form.nombre) }}
class UsuarioType extends AbstractType{ public function buildForm(FormBuilder $builder, array $options) { $builder ->add('nombre') ->add('apellidos') ->add('email') ->... ->add('ciudad') ; }
public function getName() { return 'cupon_backendbundle_usuariotype'; }}
class UsuarioType extends AbstractType{ public function buildForm(FormBuilder $builder, array $options) { $builder ->add('nombre') ->add('apellidos') ->add('email') ->... ->add('ciudad') ; }
public function getName() { return 'cupon_backendbundle_usuariotype'; }}
<strong>Label</strong>: Valor
<strong>Label</strong>: Valor
<strong>{{ form.nombreCampo.vars.label }}</strong>:{{ form. nombreCampo.vars.value }}
<strong>Label</strong>: Valor
<strong>{{ form.nombreCampo.vars.label }}</strong>:{{ form. nombreCampo.vars.value }}
AVANZADOINTERMEDIOBÁSICO1.*
CONSTANTES
{{ constant() }}
{{ constant('Symfony\\Component\\HttpKernel\\Kernel::VERSION') }}
{{ constant('Symfony\\Component\\HttpKernel\\Kernel::VERSION') }}
namespace Symfony\Component\HttpKernel;
abstract class Kernel implements KernelInterface{ // ...
const VERSION = '2.0.15';}
namespace Symfony\Component\HttpKernel;
abstract class Kernel implements KernelInterface{ // ...
const VERSION = '2.1.0-DEV'; const VERSION_ID = '20100'; const MAJOR_VERSION = '2'; const MINOR_VERSION = '1'; const RELEASE_VERSION = '0'; const EXTRA_VERSION = 'DEV';}
AVANZADOINTERMEDIOBÁSICO1.*
REDEFINE LOS FILTROS POR
DEFECTO
{{ array|sort }}
asort()arsort()krsort()ksort()rsort()shuffle()sort()usort()
array_multisort()natcasesort()natsort()rsort()shuffle()uasort()uksort()
¿Dónde se definen los filtros, etiquetas
y tags de Twig?
class Twig_Extension_Core extends Twig_Extension { public function getTokenParsers() { return array( new Twig_TokenParser_For(), new Twig_TokenParser_If(), new Twig_TokenParser_Extends(), new Twig_TokenParser_Include(), new Twig_TokenParser_Block(), // ... ); }
public function getFilters() { $filters = array( 'format' => new Twig_Filter_Function('sprintf'), 'replace' => new Twig_Filter_Function('strtr'), 'abs' => new Twig_Filter_Function('abs'), // ... ); }}
lib/twig/Extesion/Core.php
/** * Sorts an array. * * @param array $array An array */function twig_sort_filter($array){ asort($array);
return $array;}
{{ array|sort }}
natcasesort()
a0, A1, a2, a10, ...
class MiCoreExtension extends Twig_Extension_Core { // ...}
class MiCoreExtension extends Twig_Extension_Core {
public function getFilters() { // ... }}
class MiCoreExtension extends Twig_Extension_Core {
public function getFilters() { return array_merge( parent::getFilters(), array( ... ) ); }}
$twig = new Twig_Environment($loader, array( ... ));
$twig->addExtension(new MiCoreExtension());
class MiCoreExtension extends Twig_Extension_Core{ public function getFilters() { return array_merge(parent::getFilters(), array( 'sort' => new Twig_Filter_Method($this, 'sortFilter') )); }
public function sortFilter($array) { natcasesort($array); return $array; }}
function twig_sort_filter($array){ natcasesort($array); return $array;}
{{ array|sort }}
AVANZADOINTERMEDIOBÁSICO1.5
TODO SON EXPRESIONES
{% include 'seccion_' ~ oferta.categoria ~ '.twig' %}
{% for i in (1+3)//2..2**(3-1) %}
{% endfor %}
{% set ofertas = { ('oferta' ~ oferta.id): '...', (3 ~ '_' ~ oferta.nombre|length): '...', (2**2+1): '...'
} %}
{% set ofertas = { ('oferta' ~ oferta.id): '...', (3 ~ '_' ~ oferta.nombre|length): '...', (2**2+1): '...'
} %}
{% set ofertas = { oferta7040: '...', 3_57: '...', 5: '...'
} %}
AVANZADOINTERMEDIOBÁSICO1.8
EMBED
{% include %} {% extends %}
{% embed %}
{% include '...' %}
{% extends '...' %}
{% embed '...' %}
{% embed "lateral.twig" %} {% block principal %} ... {% endblock %}{% endembed %}
{% embed "lateral.twig" %} {% block secundario %} ... {% endblock %}{% endembed %}
{% include 'plantilla.twig' %}
{% embed 'plantilla.twig' %}{% endembed %}
AVANZADOINTERMEDIOBÁSICO1.8
ESCAPING AUTOMÁTICO
{% filter escape('js') %} <script type="text/javascript"> var texto = "<p>Lorem ipsum dolor sit amet</p>"; alert(texto); </script>{% endfilter %}
{% filter escape('html') %} <script type="text/javascript"> var texto = "<p>Lorem ipsum dolor sit amet</p>"; alert(texto); </script>{% endfilter %}
\x3cscript type\x3d\x22text\x2fjavascript\x22\x3e\x0a var texto \x3d \x22\x3cp\x3eLorem ipsum dolor sit amet\x3c\x2fp\x3e\x22\x3b\x0a alert\x28texto\x29\x3b\x0a \x3c\x2fscript\x3e\x0a
<script type="text/javascript"> var texto = "<p>Lorem ipsum dolor sit amet</p>"; alert(texto);</script>
{{ variable|e }}{{ variable|e('html') }}{{ variable|escape('js') }}{{ variable|e('js') }}
{% autoescape %} ........... {% endautoescape %}
{% autoescape 'html' %} ... {% endautoescape %}
{% autoescape 'js' %} ....... {% endautoescape %}
{% autoescape false %} .... {% endautoescape %}
$twig = new Twig_Environment($loader, array( 'autoescape' => function($nombre_plantilla) { return decide_escape($nombre_plantilla); }));
$twig = new Twig_Environment($loader, array( 'autoescape' => function($nombre_plantilla) { return decide_escape($nombre_plantilla); }));
function decide_escape($plantilla) { $extension = substr($plantilla, strrpos($plantilla, '.') + 1);
switch ($extension) { 'js': return 'js'; default: return 'html'; }}
AVANZADOINTERMEDIOBÁSICO1.6
RANDOM
{{ random() }}
{{ random() }}{{ random(10) }}
{{ random() }}{{ random(10) }}{{ random("abcde") }}
{{ random() }}{{ random(10) }}{{ random("abcde") }}{{ random(['a', 'b', 'c']) }}
AVANZADOINTERMEDIOBÁSICO1.5
FUNCIONES DINÁMICAS
the_ID()the_title()the_time()the_content()the_category()the_shortlink()
the_ID()the_title()the_time()the_content()the_category()the_shortlink()
the_ID()the_title()the_time()the_content()the_category()the_shortlink()
the_*()
$twig->addFunction(
'the_*', new Twig_Function_Function('wordpress'));
function wordpress($funcion, $opciones){ // ...}
$twig->addFunction(
'the_*', new Twig_Function_Function('wordpress'));
function wordpress($funcion, $opciones){ // ...}
{{ the_ID() }}
{{ the_ID() }}function wordpress('ID', array()) { ... }
{{ the_ID() }}function wordpress('ID', array()) { ... }
{{ the_content() }}
{{ the_ID() }}function wordpress('ID', array()) { ... }
{{ the_content() }}function wordpress('content', array()) { ... }
{{ the_title('<h3>', '</h3>') }}
function wordpress('title', array( '<h3>', '</h3>')) { ... }
next_image_link()next_post_link()next_posts_link()previous_image_link()previous_post_link()previous_posts_link()
*_*_link()
php_*()
AVANZADOINTERMEDIOBÁSICO1.5
FILTROS DINÁMICOS
{{ 'now'|fecha_corta }}{{ 'now'|fecha_larga }}
fecha_*()
$twig->addFilter(
'fecha_*', new Twig_Filter_Function('fecha'));
function fecha($funcion, $opciones){ // ...}
AVANZADOINTERMEDIOBÁSICO1.*
VARIABLES GLOBALES
{{ app.security }}{{ app.user }}
{{ app.request }}{{ app.session }}
{{ app.environment }}{{ app.debug }}
{{ _charset }}{{ _context }}{{ _self }}
{{ _charset }}
UTF-8
{{ _context }}
{% for i in _context|keys %} {{ i }}
{% endfor %}
{{ _context }}
{% for i in _context|keys %} {{ i }}
{% endfor %}
appassetic_parentofertaciudad_por_defectociudadSeleccionadaexpirada...
{{ _context }}
{% for i in _context|keys %} {{ i }}
{% endfor %}
appassetic_parentofertaciudad_por_defectociudadSeleccionadaexpirada...
appassetic_parent
{{ _context }}
{{ variable|mi_filtro(_context) }}
{{ _context }}
{{ variable|mi_filtro(_context) }}
SÓLO SI NO HAY OTRO REMEDIO
{{ _self }}
Twig_Template
{{ _self.getTemplateName }}
OfertaBundle:Default:includes/oferta.html.twig
{{ _self }}
title, stylesheets, rss, javascripts, id, body
{{ _self.blocks|keys|join(", ") }}
{{ _self }}
title, stylesheets, rss, javascripts, id, body
{{ _self.blocks|keys|join(", ") }}
{{ _self }}
SÓLO SI NO HAY OTRO REMEDIO
AVANZADOINTERMEDIOBÁSICO1.*
EL SANDBOX
DEMO
AVANZADOINTERMEDIOBÁSICO1.6
DATE
{{ 'now'|date("d/m/Y H:i:s") }}
{{ 'now'|date("d/m/Y H:i:s", "America/Argentina/Buenos_Aires") }}
{{ 'now'|date("d/m/Y H:i:s", "America/Havana") }}
{{ 'now'|date("d/m/Y H:i:s", "America/Caracas") }}
{{ 'now'|date("d/m/Y H:i:s", "America/Lima") }}
España: 11/06/2012 10:45:22
Argentina: 11/06/2012 05:45:22
Cuba: 11/06/2012 04:45:22
Venezuela: 11/06/2012 04:15:22
Perú: 11/06/2012 03:45:22
$twig = new Twig_Environment($loader);
$twig->getExtension('core') ->setDateFormat('d-m-Y H:i:s', '%d días');
$twig->getExtension('core') ->setTimezone('America/Montevideo');
date()
{{ date() }}
{{ date() }}
{{ date()|date() }}
{{ date() }}
{{ date()|date("d/m/Y") }}
{{ date()|date() }}
Tu invitación caduca el{{ date('+2days')|date }}
{% if date(nacimiento) < date('-18years') %} ¡Eres menor de edad!{% endif %}
La última sorpresa de #deSymfony se desvelará el {{ date('next Monday')|date() }}
Tu invitación caduca el{{ date('+2days')|date }}
Tu invitación caduca el{{ date('+2days')|date }}
{% if date(nacimiento) < date('-18years') %} ¡Eres menor de edad!{% endif %}
La última sorpresa de #deSymfony se desvelará el {{ date('next Monday')|date() }}
Tu invitación caduca el{{ date('+2days')|date }}
{% if date(fechaNacimiento) < date('-18years') %} ¡Eres menor de edad!{% endif %}
La última sorpresa de #deSymfony se desvelará el{{ date('next Monday')|date() }}
AVANZADOINTERMEDIOBÁSICO1.*
OPERADORES PROPIOS
$loader = new Twig_Loader_Filesystem(...);$twig = new Twig_Environment($loader, array(...));
$twig->addExtension(new OperatorsExtension());
{{ 5 >> 2 }}
{{ 4 >> 20 }}
Operador "quédate con el mayor"
5
20
class OperatorsExtension extends Twig_Extension{ public function getName() { return 'OperatorsExtension'; }
public function getOperators() { return array( array(), array('>>' => array( 'precedence' => 20, 'class' => 'Desymfony\Operators\MaxOperator', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT ) )); }}
class OperatorsExtension extends Twig_Extension{ public function getName() { return 'OperatorsExtension'; }
public function getOperators() { return array( array(), array('>>' => array( 'precedence' => 20, 'class' => 'Desymfony\Operators\MaxOperator', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT ) )); }}
class OperatorsExtension extends Twig_Extension{ public function getName() { return 'OperatorsExtension'; }
public function getOperators() { return array( array(), array('>>' => array( 'precedence' => 20, 'class' => 'Desymfony\Operators\MaxOperator', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT ) )); }}
!= 20+ 30** 200
PrecedenceOperador
2 +3**2 / 4 .. 4-5//2
{{ a >> b }} max($a, $b);
TWIG PHP
class MaxOperator extends Twig_Node_Expression_Binary{ public function compile(Twig_Compiler $compiler) { $compiler ->raw('max(') ->subcompile($this->getNode('left')) ->raw(', ') ->subcompile($this->getNode('right')) ->raw(')') ; }
class MaxOperator extends Twig_Node_Expression_Binary{ public function compile(Twig_Compiler $compiler) { $compiler ->raw('max(') ->subcompile($this->getNode('left')) ->raw(', ') ->subcompile($this->getNode('right')) ->raw(')') ; } max($a, $b);
// line 23echo twig_escape_filter($this->env, max(5, 2), "html", null, true);
$compiler ->raw() ->write() ->string() ->indent() ->outdent();
(literal)(indentado)(entrecomillado)(indentar)(desindentar)
Operador "cambia claves por valores"
array_flip(range('a', 'z'))
{% for i in <->('a'..'z') %} {{ i }},{% endfor %}
TWIG
PHP
Operador "cambia claves por valores"
array_flip(range('a', 'z'))
{% for i in <->('a'..'z') %} {{ i }},{% endfor %}
TWIG
PHP
class OperatorsExtension extends Twig_Extension{ public function getName() { return 'OperatorsExtension'; }
public function getOperators() { return array( array('<->' => array( 'precedence' => 50, 'class' => 'Desymfony\Operators\FlipOperator', ), array() )); }}
class OperatorsExtension extends Twig_Extension{ public function getName() { return 'OperatorsExtension'; }
public function getOperators() { return array( array('<->' => array( 'precedence' => 50, 'class' => 'Desymfony\Operators\FlipOperator', ), array() )); }}
class OperatorsExtension extends Twig_Extension{ public function getName() { return 'OperatorsExtension'; }
public function getOperators() { return array( array('<->' => array( 'precedence' => 50, 'class' => 'Desymfony\Operators\FlipOperator', ), array() )); }}
namespace Desymfony\Operators;
class FlipOperator extends Twig_Node_Expression_Unary{
public function compile(Twig_Compiler $compiler) { $compiler ->raw("array_flip(") ->subcompile($this->getNode('node')) ->raw(")") ; }
namespace Desymfony\Operators;
class FlipOperator extends Twig_Node_Expression_Unary{
public function compile(Twig_Compiler $compiler) { $compiler ->raw("array_flip(") ->subcompile($this->getNode('node')) ->raw(")") ; } array_flip($coleccion);
// line 17
$context['_parent'] = (array) $context;
$context['_seq'] = twig_ensure_traversable(array_flip(range("a", "z")));
foreach ($context['_seq'] as $context["_key"] => $context["i"]) {
// line 18
echo " ";
if (isset($context["i"])) { $_i_ = $context["i"]; } else { $_i_ = null; }
echo twig_escape_filter($this->env, $_i_, "html", null, true);
echo ",";
}
// line 17
$context['_parent'] = (array) $context;
$context['_seq'] = twig_ensure_traversable(array_flip(range("a", "z")));
foreach ($context['_seq'] as $context["_key"] => $context["i"]) {
// line 18
echo " ";
if (isset($context["i"])) { $_i_ = $context["i"]; } else { $_i_ = null; }
echo twig_escape_filter($this->env, $_i_, "html", null, true);
echo ",";
}
AVANZADOINTERMEDIOBÁSICO1.*
SUPER CACHÉ
# mkfs -q /dev/ram1 65536# mkdir -p /twigcache# mount /dev/ram1 /twigcache
Inspirado por: http://www.cyberciti.biz/faq/howto!create!linux!ram!disk!filesystem/
$twig = new \Twig_Environment( $loader, array('cache' => '/twigcache'));
# app/config/config.ymltwig: cache: '/twigcache'
AVANZADOINTERMEDIOBÁSICO1.*
ETIQUETASPROPIAS
#1#2 #3
etiquetas
operadorestests
{% source 'simple.twig' %}
{% source '../../../composer.json' %}
1. Clase Token Parser
2. Clase NodeTWIG PHP
TWIGTWIG
$loader = new Twig_Loader_Filesystem(...);$twig = new Twig_Environment($loader, array(...));
$twig->addTokenParser(new SourceTokenParser());
class SourceTokenParser extends Twig_TokenParser{ public function getTag() { return 'source'; }}
{% source '...' %}
namespace Desymfony\Tags;use Desymfony\Tags\SourceNode;
class SourceTokenParser extends Twig_TokenParser{ public function parse(Twig_Token $token) { $lineno = $token->getLine(); $value = $this->parser->getExpressionParser()->parseExpression();
$this->parser->getStream()->expect(Twig_Token::BLOCK_END_TYPE);
return new SourceNode($value, $lineno, $this->getTag()); }}
namespace Desymfony\Tags;
class SourceNode extends Twig_Node{ public function __construct(Twig_Node_Expression $value, $lineno, $tag = null) { parent::__construct(array('file' => $value), array(), $lineno, $tag); }
public function compile(Twig_Compiler $compiler) {
$compiler -> // ... ->write('echo file_get_contents(') ->subcompile($this->getNode('file')) ->raw(');'); ; }}
// line 3echo file_get_contents("simple.twig");// line 4echo "\n";
// line 5echo file_get_contents("../../../composer.json");// line 6echo "\n";
AVANZADOINTERMEDIOBÁSICO1.5
INTERPOLACIÓN
La oferta cuesta 25.78 euros (30.42 con IVA) y es válida hasta el 10/06/2012
La oferta cuesta 25.78 euros (30.42 con IVA) y es válida hasta el 10/06/2012
{{ 'La oferta cuesta ' ~ oferta.precio ~ ' euros (' ~ oferta.precio*1.18 ~ ' con IVA) y es válida hasta el ' ~ oferta.fechaExpiracion|date() }}
La oferta cuesta 25.78 euros (30.42 con IVA) y es válida hasta el 10/06/2012
~
{{ 'La oferta cuesta %.2f euros (%.2f con IVA) y es
válida hasta el %s'|format(oferta.precio, oferta.precio*1.18, oferta.fechaExpiracion|date()) }}
La oferta cuesta 25.78 euros (30.42 con IVA) y es válida hasta el 10/06/2012
format()
{{ 'La oferta cuesta :precio euros (:total con IVA) y es válida hasta el :fecha'|replace({ ':precio': oferta.precio, ':total': oferta.precio*1.18, ':fecha': oferta.fechaExpiracion|date() }) }}
La oferta cuesta 25.78 euros (30.42 con IVA) y es válida hasta el 10/06/2012
replace()
{{ "La oferta cuesta #{oferta.precio} euros (#{oferta.precio*1.18} con IVA) y es válida hasta el#{oferta.fechaExpiracion|date()}" }}
La oferta cuesta 25.78 euros (30.42 con IVA) y es válida hasta el 10/06/2012
{{ "... #{ expresión } ..." }}
{{ "... #{ expresión } ..." }}
AVANZADOINTERMEDIOBÁSICO1.5
NUEVOS FILTROS Y ETIQUETAS
{% flush %}
{% do %}
{{ 1 + 1 }}
{% do 1 + 1 %}
2
(nada)
{% set lista = ['a', 'b', 'c', 'd'] %}
{{ lista|shift }}
{% do lista|shift %}
Fuente: https://github.com/fabpot/Twig/issues/446
[ : ]
{% set lista = ['a', 'b', 'c', 'd'] %}
{{ lista[1:] }}
{% set lista = ['a', 'b', 'c', 'd'] %}
{{ lista[-1:] }}
{% set lista = ['a', 'b', 'c', 'd'] %}
{{ lista[2:2] }}
{{ '@username'[1:] }}
{{ 'Lorem ipsum...'[-4:10] }}
$a ^ $b
$a << $b
$a >> $b
{{ a b-and b }}
{{ a b-xor b }}
{{ a b-or b }}
operadores bitwise
PHPTWIG
AVANZADOINTERMEDIOBÁSICO1.*
TWIG_TEMPLATE
<html> <head> ... </head>
<body> ...
<span data-host="Darwin mbp.local 10.8.0 Darwin Kernel Version 10.8.0: Tue Jun 7 16:33:36 PDT 2011; root:xnu-1504.15.3~1/RELEASE_I386 i386" data-elapsed="0.97804594039917 sec." data-timestamp="1339609672.9781"></span>
</body></html>
app/cache/dev/twig/
app/cache/dev/twig/
<?php
/* ::frontend.html.twig */class __TwigTemplate_09fc2d8a188dda8245d295e6324582f2 extends Twig_Template{ public function __construct(Twig_Environment $env) { parent::__construct($env);
$this->parent = $this->env->loadTemplate("::base.html.twig");
$this->blocks = array( 'stylesheets' => array($this, 'block_stylesheets'), 'javascripts' => array($this, 'block_javascripts'), 'body' => array($this, 'block_body'), 'article' => array($this, 'block_article'), ); }}
app/cache/dev/twig/09/fc/2d8a188dda8245d295e6324582f2.php
class __TwigTemplate_09f...2f2 extends Twig_Template{ // ...}
namespace Cupon\BackendBundle\Controller;use Symfony\Bundle\FrameworkBundle\Controller\Controller;
class UsuarioController extends Controller{ public function indexAction() { //... return $this->render( 'BackendBundle:Usuario:index.html.twig', array( ... ) ); }}
function render($view, $parameters, $response) {
return $this->container->get('templating') ->renderResponse($view, $parameters, $response);
}
Symfony/Bundle/FrameworkBundle/Controller/Controller.php
public function render($name, array $context = array()){ return $this->loadTemplate($name) ->render($context);}
lib/Twig/Environment.php
return $this->render( ... );
render( ... ) Twig_Template
return $this->render( ... );
render( ... ) Twig_Template
<html> <head> ... </head>
<body> ...
<span data-host="Darwin mbp.local 10.8.0 Darwin Kernel Version 10.8.0: Tue Jun 7 16:33:36 PDT 2011; root:xnu-1504.15.3~1/RELEASE_I386 i386" data-elapsed="0.97804594039917 sec." data-timestamp="1339609672.9781"></span>
</body></html>
$loader = new Twig_Loader_Filesystem(__DIR__.'/../Resources/views');$twig = new Twig_Environment($loader, array( 'base_template_class' => '\Desymfony\Template\MiTwigTemplate',));
# app/config/config.ymltwig: base_template_class: "Desymfony\Template\MiTwigTemplate"
base_template_class
namespace Desymfony\Template;
abstract class MiTwigTemplate extends Twig_Template{ public function render(array $context) { $traza = sprintf('<span data-host="%s" data-elapsed="%s sec." data-timestamp="%s"></span>', php_uname(), microtime(true)-$_SERVER['REQUEST_TIME'], microtime(true) );
return str_replace('</body>', $traza."\n</body>", parent::render($context) ); }}
AVANZADOINTERMEDIOBÁSICO1.*
TWIG LINTER
$twig = new Twig_Environment($loader, array(..));
try { $twig->parse($twig->tokenize($plantilla)); echo "[OK] La sintaxis de la plantilla es correcta";} catch (Twig_Error_Syntax $e) { echo "[ERROR] La plantilla tiene errores de sintaxis";}
$ php app/console twig:lint @MyBundle
$ php app/console twig:lint src/Cupon/OfertaBundle/Resources/views/index.html.twig
twig:lint
twig:lint
SYMFONY 2.1
twig:lint
SYMFONY 2.1
DESYMFONY 2013
¡muchas gracias!
Contacto
• github.com/javiereguiluz
• twitter.com/javiereguiluz
• linkd.in/javiereguiluz