twig, los mejores trucos y técnicas avanzadas

Post on 11-May-2015

10.328 Views

Category:

Technology

4 Downloads

Preview:

Click to see full reader

TRANSCRIPT

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

&lt;script type=&quot;text/javascript&quot;&gt; var texto = &quot;&lt;p&gt;Lorem ipsum dolor sit amet&lt;/p&gt;&quot;; alert(texto);&lt;/script&gt;

{{ 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

• javier.eguiluz@gmail.com

• github.com/javiereguiluz

• twitter.com/javiereguiluz

• linkd.in/javiereguiluz

top related