Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
branch: gh-pages
Fetching contributors…

Cannot retrieve contributors at this time

824 lines (776 sloc) 69.514 kB
<!DOCTYPE html>
<html lang="es">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Extendiendo Twig &mdash; Manual de Twig en Español</title>
<link rel="stylesheet" href="_static/tnp.css" type="text/css" />
<link rel="stylesheet" href="_static/pygments.css" type="text/css" />
<script type="text/javascript">
var DOCUMENTATION_OPTIONS = {
URL_ROOT: '',
VERSION: 'v1.12.0-RC1',
COLLAPSE_INDEX: false,
FILE_SUFFIX: '.html',
HAS_SOURCE: true
};
</script>
<script type="text/javascript" src="_static/jquery.js"></script>
<script type="text/javascript" src="_static/underscore.js"></script>
<script type="text/javascript" src="_static/doctools.js"></script>
<script type="text/javascript" src="_static/translations.js"></script>
<link rel="shortcut icon" href="_static/icotnp.ico"/>
<link rel="top" title="Manual de Twig en Español" href="index.html" />
<link rel="next" title="Twig por dentro" href="internals.html" />
<link rel="prev" title="Twig para desarrolladores" href="api.html" />
</head>
<body>
<div class="imalogo">
<a href="index.html"><img src="http://gitnacho.github.com/tnp/img/twig/twig-logo.png" alt="Traducciones de Nacho Pacheco" />
<a href="index.html"><img src="http://gitnacho.github.com/tnp/_static/normaltnp.png" alt="Traducciones de Nacho Pacheco" /></a>
<div class="social">
<a href="https://twitter.com/share" class="twitter-share-button" data-via="esymfony" data-lang="es">Tweet</a>
<script>!function(d,s,id){var js,fjs=d.getElementsByTagName(s)[0];if(!d.getElementById(id)){js=d.createElement(s);js.id=id;js.src="//platform.twitter.com/widgets.js";fjs.parentNode.insertBefore(js,fjs);}}(document,"script","twitter-wjs");</script>
</div>
<div id="searchbox">
<form class="searc " action="search.html" method="get">
<input type="search" name="q" placeholder="Término a buscar" />
<input type="submit" value="Ir" />
<input type="hidden" name="check_keywords" value="yes" />
<input type="hidden" name="area" value="default" />
</form>
<script type="text/javascript">$('#searchbox').show(0);</script>
</div>
<div class="related">
<h3>Navegación</h3>
<ul>
<li class="right" style="margin-right: 10px">
<a href="genindex.html" title="Índice General"
accesskey="I">índice</a></li>
<li class="right" >
<a href="internals.html" title="Twig por dentro"
accesskey="N">siguiente</a> |</li>
<li class="right" >
<a href="api.html" title="Twig para desarrolladores"
accesskey="P">anterior</a> |</li>
<li><a href="index.html">Twig en Español</a> &raquo;</li>
</ul>
</div>
</div>
<div class="document">
<div class="documentwrapper">
<div class="bodywrapper">
<div class="body">
<div class="section" id="extendiendo-twig">
<h1>Extendiendo <em>Twig</em><a class="headerlink" href="#extendiendo-twig" title="Enlazar permanentemente con este título">¶</a></h1>
<div class="admonition caution">
<p class="first admonition-title">Prudencia</p>
<p class="last">Esta sección describe cómo extender <em>Twig</em> a partir de <strong>Twig 1.12</strong>. Si estás usando una versión anterior, en vez de esta lee el capítulo del <a class="reference internal" href="advanced_legacy.html"><em>legado</em></a>.</p>
</div>
<p><em>Twig</em> se puede extender en muchos aspectos; puedes añadir etiquetas adicionales, filtros, pruebas, operadores, variables globales y funciones. Incluso puedes extender el propio analizador con visitantes de nodo.</p>
<div class="admonition note">
<p class="first admonition-title">Nota</p>
<p class="last">La primer sección de este capítulo describe la forma de extender <em>Twig</em> fácilmente. Si deseas volver a utilizar tus cambios en diferentes proyectos o si deseas compartirlos con los demás, entonces, debes crear una extensión tal como se describe en la siguiente sección.</p>
</div>
<div class="admonition caution">
<p class="first admonition-title">Prudencia</p>
<p class="last">Al extender <em>Twig</em> sin crear una extensión, <em>Twig</em> no será capaz de volver a compilar tus plantillas al actualizar el código de <em>PHP</em>. Para ver tus cambios en tiempo real, o bien desactiva la memorización de plantillas o empaca tu código en una extensión (ve la siguiente sección de este capítulo).</p>
</div>
<p>Antes de extender <em>Twig</em>, debes entender las diferencias entre todos los diferentes puntos de extensión posibles y cuándo utilizarlos.</p>
<p>En primer lugar, recuerda que el lenguaje de <em>Twig</em> tiene dos construcciones principales:</p>
<ul class="simple">
<li><tt class="docutils literal"><span class="pre">{{</span> <span class="pre">}}</span></tt>: Utilizada para imprimir el resultado de la evaluación de la expresión;</li>
<li><tt class="docutils literal"><span class="pre">{%</span> <span class="pre">%}</span></tt>: Utilizada para ejecutar instrucciones.</li>
</ul>
<p>Para entender por qué <em>Twig</em> expone tantos puntos de extensión, vamos a ver cómo implementar un generador <em>Lorem ipsum</em> (este necesita saber el número de palabras a generar).</p>
<p>Puedes utilizar una <em>etiqueta</em> <tt class="docutils literal"><span class="pre">Lipsum</span></tt>:</p>
<div class="highlight-jinja"><div class="highlight"><pre><span class="cp">{%</span> <span class="k">lipsum</span> <span class="m">40</span> <span class="cp">%}</span><span class="x"></span>
</pre></div>
</div>
<p>Eso funciona, pero usar una etiqueta para <tt class="docutils literal"><span class="pre">lipsum</span></tt> no es una buena idea por al menos tres razones principales:</p>
<ul>
<li><p class="first"><tt class="docutils literal"><span class="pre">lipsum</span></tt> no es una construcción del lenguaje;</p>
</li>
<li><p class="first">La etiqueta produce algo;</p>
</li>
<li><p class="first">La etiqueta no es flexible ya que no la puedes utilizar en una expresión:</p>
<div class="highlight-jinja"><pre>{{ 'algún texto' ~ {% lipsum 40 %} ~ 'algo más de texto' }}</pre>
</div>
</li>
</ul>
<p>De hecho, rara vez es necesario crear etiquetas; y es una muy buena noticia porque las etiquetas son el punto de extensión más complejo de <em>Twig</em>.</p>
<p>Ahora, vamos a utilizar un <em>filtro</em> <tt class="docutils literal"><span class="pre">lipsum</span></tt>:</p>
<div class="highlight-jinja"><div class="highlight"><pre><span class="cp">{{</span> <span class="m">40</span><span class="o">|</span><span class="nf">lipsum</span> <span class="cp">}}</span><span class="x"></span>
</pre></div>
</div>
<p>Una vez más, funciona, pero se ve raro. Un filtro transforma el valor pasado a algo más pero aquí utilizamos el valor para indicar el número de palabras a generar (así que, <tt class="docutils literal"><span class="pre">40</span></tt> es un argumento del filtro, no el valor que se va a transformar).</p>
<p>En seguida, vamos a utilizar una <em>función</em> <tt class="docutils literal"><span class="pre">lipsum</span></tt>:</p>
<div class="highlight-jinja"><div class="highlight"><pre><span class="cp">{{</span> <span class="nv">lipsum</span><span class="o">(</span><span class="m">40</span><span class="o">)</span> <span class="cp">}}</span><span class="x"></span>
</pre></div>
</div>
<p>Aquí vamos. Para este ejemplo concreto, la creación de una función es el punto de extensión a usar. Y la puedes usar en cualquier lugar en que se acepte una expresión:</p>
<div class="highlight-jinja"><div class="highlight"><pre><span class="cp">{{</span> <span class="s1">&#39;some text&#39;</span> <span class="o">~</span> <span class="nv">lipsum</span><span class="o">(</span><span class="m">40</span><span class="o">)</span> <span class="o">~</span> <span class="s1">&#39;some more text&#39;</span> <span class="cp">}}</span><span class="x"></span>
<span class="cp">{%</span> <span class="k">set</span> <span class="nv">lipsum</span> <span class="o">=</span> <span class="nv">lipsum</span><span class="o">(</span><span class="m">40</span><span class="o">)</span> <span class="cp">%}</span><span class="x"></span>
</pre></div>
</div>
<p>Por último pero no menos importante, también puedes utilizar un objeto <em>global</em> con un método capaz de generar texto <em>Lorem Ipsum</em>:</p>
<div class="highlight-jinja"><div class="highlight"><pre><span class="cp">{{</span> <span class="nv">text.lipsum</span><span class="o">(</span><span class="m">40</span><span class="o">)</span> <span class="cp">}}</span><span class="x"></span>
</pre></div>
</div>
<p>Como regla general, utiliza funciones para las características más utilizadas y objetos globales para todo lo demás.</p>
<p>Ten en cuenta lo siguiente cuando quieras extender <em>Twig</em>:</p>
<table border="1" class="docutils">
<colgroup>
<col width="12%" />
<col width="35%" />
<col width="22%" />
<col width="32%" />
</colgroup>
<thead valign="bottom">
<tr class="row-odd"><th class="head">¿Qué?</th>
<th class="head">¿dificultad para implementarlo?</th>
<th class="head">¿Con qué frecuencia?</th>
<th class="head">¿Cuándo?</th>
</tr>
</thead>
<tbody valign="top">
<tr class="row-even"><td><em>macro</em></td>
<td>trivial</td>
<td>frecuente</td>
<td>Generación de contenido</td>
</tr>
<tr class="row-odd"><td><em>global</em></td>
<td>trivial</td>
<td>frecuente</td>
<td>Objeto ayudante</td>
</tr>
<tr class="row-even"><td><em>function</em></td>
<td>trivial</td>
<td>frecuente</td>
<td>Generación de contenido</td>
</tr>
<tr class="row-odd"><td><em>filter</em></td>
<td>trivial</td>
<td>frecuente</td>
<td>Transformación de valor</td>
</tr>
<tr class="row-even"><td><em>tag</em></td>
<td>complejo</td>
<td>raro</td>
<td>Constructor del lenguaje <em>DSL</em></td>
</tr>
<tr class="row-odd"><td><em>test</em></td>
<td>trivial</td>
<td>raro</td>
<td>Decisión booleana</td>
</tr>
<tr class="row-even"><td><em>operator</em></td>
<td>trivial</td>
<td>raro</td>
<td>Transformación de valores</td>
</tr>
</tbody>
</table>
<div class="section" id="globales">
<h2>Globales<a class="headerlink" href="#globales" title="Enlazar permanentemente con este título">¶</a></h2>
<p>Una variable global es como cualquier otra variable de plantilla, excepto que está disponible en todas las plantillas y macros:</p>
<div class="highlight-php"><div class="highlight"><pre><span class="nv">$twig</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">Twig_Environment</span><span class="p">(</span><span class="nv">$loader</span><span class="p">);</span>
<span class="nv">$twig</span><span class="o">-&gt;</span><span class="na">addGlobal</span><span class="p">(</span><span class="s1">&#39;text&#39;</span><span class="p">,</span> <span class="k">new</span> <span class="nx">Text</span><span class="p">());</span>
</pre></div>
</div>
<p>Entonces puedes utilizar la variable <tt class="docutils literal"><span class="pre">text</span></tt> en cualquier parte de una plantilla:</p>
<div class="highlight-jinja"><div class="highlight"><pre><span class="cp">{{</span> <span class="nv">text.lipsum</span><span class="o">(</span><span class="m">40</span><span class="o">)</span> <span class="cp">}}</span><span class="x"></span>
</pre></div>
</div>
</div>
<div class="section" id="filtros">
<h2>Filtros<a class="headerlink" href="#filtros" title="Enlazar permanentemente con este título">¶</a></h2>
<p>Crear un filtro es tan sencillo como asociar un nombre con un ejecutable <em>PHP</em>:</p>
<div class="highlight-php"><div class="highlight"><pre><span class="c1">// una función anónima</span>
<span class="nv">$filter</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">Twig_SimpleFilter</span><span class="p">(</span><span class="s1">&#39;rot13&#39;</span><span class="p">,</span> <span class="k">function</span> <span class="p">(</span><span class="nv">$string</span><span class="p">)</span> <span class="p">{</span>
<span class="k">return</span> <span class="nb">str_rot13</span><span class="p">(</span><span class="nv">$string</span><span class="p">);</span>
<span class="p">});</span>
<span class="c1">// o una simple función PHP</span>
<span class="nv">$filter</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">Twig_SimpleFilter</span><span class="p">(</span><span class="s1">&#39;rot13&#39;</span><span class="p">,</span> <span class="s1">&#39;str_rot13&#39;</span><span class="p">);</span>
<span class="c1">// o un método de clase</span>
<span class="nv">$filter</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">Twig_SimpleFilter</span><span class="p">(</span><span class="s1">&#39;rot13&#39;</span><span class="p">,</span> <span class="k">array</span><span class="p">(</span><span class="s1">&#39;SomeClass&#39;</span><span class="p">,</span> <span class="s1">&#39;rot13Filter&#39;</span><span class="p">));</span>
</pre></div>
</div>
<p>El primer argumento pasado al constructor de <tt class="docutils literal"><span class="pre">Twig_Filter_Function</span></tt> es el nombre del filtro que usarás en las plantillas y el segundo es el ejecutable <em>PHP</em> asociado.</p>
<p>Luego, añade el filtro a tu entorno <em>Twig</em>:</p>
<div class="highlight-php"><div class="highlight"><pre><span class="nv">$twig</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">Twig_Environment</span><span class="p">(</span><span class="nv">$loader</span><span class="p">);</span>
<span class="nv">$twig</span><span class="o">-&gt;</span><span class="na">addFilter</span><span class="p">(</span><span class="nv">$filter</span><span class="p">);</span>
</pre></div>
</div>
<p>Y aquí tienes cómo utilizarlo en una plantilla:</p>
<div class="highlight-jinja"><div class="highlight"><pre><span class="cp">{{</span> <span class="s1">&#39;Twig&#39;</span><span class="o">|</span><span class="nf">rot13</span> <span class="cp">}}</span><span class="x"></span>
<span class="c">{# producirá Gjvt #}</span><span class="x"></span>
</pre></div>
</div>
<p>Cuando es llamado por <em>Twig</em>, el ejecutable <em>PHP</em> en el lado izquierdo recibe el filtro (antes de la barra vertical <tt class="docutils literal"><span class="pre">|</span></tt>) como primer argumento y los argumentos extras pasados al filtro (dentro de paréntesis <tt class="docutils literal"><span class="pre">()</span></tt>) como argumentos extra.</p>
<p>Por ejemplo, el siguiente código:</p>
<div class="highlight-jinja"><div class="highlight"><pre><span class="cp">{{</span> <span class="s1">&#39;TWIG&#39;</span><span class="o">|</span><span class="nf">lower</span> <span class="cp">}}</span><span class="x"></span>
<span class="cp">{{</span> <span class="nv">now</span><span class="o">|</span><span class="nf">date</span><span class="o">(</span><span class="s1">&#39;d/m/Y&#39;</span><span class="o">)</span> <span class="cp">}}</span><span class="x"></span>
</pre></div>
</div>
<p>se compila a algo como lo siguiente:</p>
<div class="highlight-php"><div class="highlight"><pre><span class="o">&lt;?</span><span class="nx">php</span> <span class="k">echo</span> <span class="nb">strtolower</span><span class="p">(</span><span class="s1">&#39;TWIG&#39;</span><span class="p">)</span> <span class="cp">?&gt;</span><span class="x"></span>
<span class="cp">&lt;?php</span> <span class="k">echo</span> <span class="nx">twig_date_format_filter</span><span class="p">(</span><span class="nv">$now</span><span class="p">,</span> <span class="s1">&#39;d/m/Y&#39;</span><span class="p">)</span> <span class="cp">?&gt;</span><span class="x"></span>
</pre></div>
</div>
<p>La clase <tt class="docutils literal"><span class="pre">Twig_SimpleFilter</span></tt> toma un arreglo de opciones como último argumento:</p>
<div class="highlight-php"><div class="highlight"><pre><span class="nv">$filter</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">Twig_SimpleFilter</span><span class="p">(</span><span class="s1">&#39;rot13&#39;</span><span class="p">,</span> <span class="s1">&#39;str_rot13&#39;</span><span class="p">,</span> <span class="nv">$options</span><span class="p">);</span>
</pre></div>
</div>
<div class="section" id="entorno-consciente-de-filtros">
<h3>Entorno consciente de filtros<a class="headerlink" href="#entorno-consciente-de-filtros" title="Enlazar permanentemente con este título">¶</a></h3>
<p>Si en tu filtro quieres acceder a la instancia del entorno actual, pon a <tt class="docutils literal"><span class="pre">true</span></tt> la opción <tt class="docutils literal"><span class="pre">needs_environment</span></tt>; <em>Twig</em> pasará el entorno actual como primer argumento al llamar al filtro:</p>
<div class="highlight-php"><div class="highlight"><pre><span class="nv">$filter</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">Twig_SimpleFilter</span><span class="p">(</span><span class="s1">&#39;rot13&#39;</span><span class="p">,</span> <span class="k">function</span> <span class="p">(</span><span class="nx">Twig_Environment</span> <span class="nv">$env</span><span class="p">,</span> <span class="nv">$string</span><span class="p">)</span> <span class="p">{</span>
<span class="c1">// obtiene el juego de caracteres actual, por ejemplo</span>
<span class="nv">$charset</span> <span class="o">=</span> <span class="nv">$env</span><span class="o">-&gt;</span><span class="na">getCharset</span><span class="p">();</span>
<span class="k">return</span> <span class="nb">str_rot13</span><span class="p">(</span><span class="nv">$string</span><span class="p">);</span>
<span class="p">},</span> <span class="k">array</span><span class="p">(</span><span class="s1">&#39;needs_environment&#39;</span> <span class="o">=&gt;</span> <span class="k">true</span><span class="p">));</span>
</pre></div>
</div>
</div>
<div class="section" id="filtros-conscientes-del-contexto">
<h3>Filtros conscientes del contexto<a class="headerlink" href="#filtros-conscientes-del-contexto" title="Enlazar permanentemente con este título">¶</a></h3>
<p>Si quieres acceder al contexto actual en tu filtro, pon a <tt class="docutils literal"><span class="pre">true</span></tt> la opción <tt class="docutils literal"><span class="pre">needs_context</span></tt>; <em>Twig</em> pasará el contexto actual como primer argumento al llamar al filtro (o el segundo si
<tt class="docutils literal"><span class="pre">needs_environment</span></tt> también es <tt class="docutils literal"><span class="pre">true</span></tt>):</p>
<div class="highlight-php"><div class="highlight"><pre><span class="nv">$filter</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">Twig_SimpleFilter</span><span class="p">(</span><span class="s1">&#39;rot13&#39;</span><span class="p">,</span> <span class="k">function</span> <span class="p">(</span><span class="nv">$context</span><span class="p">,</span> <span class="nv">$string</span><span class="p">)</span> <span class="p">{</span>
<span class="c1">// ...</span>
<span class="p">},</span> <span class="k">array</span><span class="p">(</span><span class="s1">&#39;needs_context&#39;</span> <span class="o">=&gt;</span> <span class="k">true</span><span class="p">));</span>
<span class="nv">$filter</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">Twig_SimpleFilter</span><span class="p">(</span><span class="s1">&#39;rot13&#39;</span><span class="p">,</span> <span class="k">function</span> <span class="p">(</span><span class="nx">Twig_Environment</span> <span class="nv">$env</span><span class="p">,</span> <span class="nv">$context</span><span class="p">,</span> <span class="nv">$string</span><span class="p">)</span> <span class="p">{</span>
<span class="c1">// ...</span>
<span class="p">},</span> <span class="k">array</span><span class="p">(</span><span class="s1">&#39;needs_context&#39;</span> <span class="o">=&gt;</span> <span class="k">true</span><span class="p">,</span> <span class="s1">&#39;needs_environment&#39;</span> <span class="o">=&gt;</span> <span class="k">true</span><span class="p">));</span>
</pre></div>
</div>
</div>
<div class="section" id="escapando-automaticamente">
<h3>Escapando automáticamente<a class="headerlink" href="#escapando-automaticamente" title="Enlazar permanentemente con este título">¶</a></h3>
<p>Si está habilitado el escape automático, puedes escapar la salida del filtro antes de imprimir. Si tu filtro actúa como un escapista (o explícitamente produce código <em>html</em> o <em>javascript</em>), desearás que se imprima la salida sin procesar. En tal caso, establece la opción <tt class="docutils literal"><span class="pre">is_safe</span></tt>:</p>
<div class="highlight-php"><div class="highlight"><pre><span class="nv">$filter</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">Twig_SimpleFilter</span><span class="p">(</span><span class="s1">&#39;nl2br&#39;</span><span class="p">,</span> <span class="s1">&#39;nl2br&#39;</span><span class="p">,</span> <span class="k">array</span><span class="p">(</span><span class="s1">&#39;is_safe&#39;</span> <span class="o">=&gt;</span> <span class="k">array</span><span class="p">(</span><span class="s1">&#39;html&#39;</span><span class="p">)));</span>
</pre></div>
</div>
<p>Algunos filtros posiblemente tengan que trabajar en entradas que ya se escaparon o son seguras, por ejemplo, al agregar etiquetas <em>HTML</em> (seguras) inicialmente inseguras para salida. En tal caso, establece la opción <tt class="docutils literal"><span class="pre">pre_escape</span></tt> para escapar los datos entrantes antes de pasarlos por tu filtro:</p>
<div class="highlight-php"><div class="highlight"><pre><span class="nv">$filter</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">Twig_SimpleFilter</span><span class="p">(</span><span class="s1">&#39;somefilter&#39;</span><span class="p">,</span> <span class="s1">&#39;somefilter&#39;</span><span class="p">,</span> <span class="k">array</span><span class="p">(</span><span class="s1">&#39;pre_escape&#39;</span> <span class="o">=&gt;</span> <span class="s1">&#39;html&#39;</span><span class="p">,</span> <span class="s1">&#39;is_safe&#39;</span> <span class="o">=&gt;</span> <span class="k">array</span><span class="p">(</span><span class="s1">&#39;html&#39;</span><span class="p">)));</span>
</pre></div>
</div>
</div>
<div class="section" id="filtros-dinamicos">
<h3>Filtros dinámicos<a class="headerlink" href="#filtros-dinamicos" title="Enlazar permanentemente con este título">¶</a></h3>
<p>Un nombre de filtro que contiene el carácter especial <tt class="docutils literal"><span class="pre">*</span></tt> es un filtro dinámico debido a que el <tt class="docutils literal"><span class="pre">*</span></tt> puede ser cualquier cadena:</p>
<div class="highlight-php"><div class="highlight"><pre><span class="nv">$filter</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">Twig_SimpleFilter</span><span class="p">(</span><span class="s1">&#39;*_path&#39;</span><span class="p">,</span> <span class="k">function</span> <span class="p">(</span><span class="nv">$name</span><span class="p">,</span> <span class="nv">$arguments</span><span class="p">)</span> <span class="p">{</span>
<span class="c1">// ...</span>
<span class="p">});</span>
</pre></div>
</div>
<p>Los siguientes filtros deben corresponder con el filtro dinámico definido anteriormente:</p>
<ul class="simple">
<li><tt class="docutils literal"><span class="pre">product_path</span></tt></li>
<li><tt class="docutils literal"><span class="pre">category_path</span></tt></li>
</ul>
<p>Un filtro dinámico puede definir más de una parte dinámica:</p>
<div class="highlight-php"><div class="highlight"><pre><span class="nv">$filter</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">Twig_SimpleFilter</span><span class="p">(</span><span class="s1">&#39;*_path&#39;</span><span class="p">,</span> <span class="k">function</span> <span class="p">(</span><span class="nv">$name</span><span class="p">,</span> <span class="nv">$suffix</span><span class="p">,</span> <span class="nv">$arguments</span><span class="p">)</span> <span class="p">{</span>
<span class="c1">// ...</span>
<span class="p">});</span>
</pre></div>
</div>
<p>El filtro recibirá todas las partes dinámicas de los valores antes de los argumentos de los filtros normales, pero después del entorno y el contexto. Por ejemplo, una llamada a <tt class="docutils literal"><span class="pre">'foo'|a_path_b()</span></tt> resultará en que se pasarán los siguientes argumentos al filtro: <tt class="docutils literal"><span class="pre">('a',</span> <span class="pre">'b',</span> <span class="pre">'foo')</span></tt>.</p>
</div>
</div>
<div class="section" id="funciones">
<h2>Funciones<a class="headerlink" href="#funciones" title="Enlazar permanentemente con este título">¶</a></h2>
<p>Las funciones están definidas exactamente de la misma manera que los filtros, pero necesitas crear una instancia de <tt class="docutils literal"><span class="pre">Twig_SimpleFunction</span></tt>:</p>
<div class="highlight-php"><div class="highlight"><pre><span class="nv">$twig</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">Twig_Environment</span><span class="p">(</span><span class="nv">$loader</span><span class="p">);</span>
<span class="nv">$function</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">Twig_SimpleFunction</span><span class="p">(</span><span class="s1">&#39;function_name&#39;</span><span class="p">,</span> <span class="k">function</span> <span class="p">()</span> <span class="p">{</span>
<span class="c1">// ...</span>
<span class="p">});</span>
<span class="nv">$twig</span><span class="o">-&gt;</span><span class="na">addFunction</span><span class="p">(</span><span class="nv">$function</span><span class="p">);</span>
</pre></div>
</div>
<p>Las funciones apoyan las mismas características que los filtros, excepto por las opciones <tt class="docutils literal"><span class="pre">pre_escapr</span></tt> y <tt class="docutils literal"><span class="pre">preserves_safety</span></tt>.</p>
</div>
<div class="section" id="pruebas">
<h2>Pruebas<a class="headerlink" href="#pruebas" title="Enlazar permanentemente con este título">¶</a></h2>
<p>Las pruebas se definen exactamente de la misma manera que los filtros y funciones, pero necesitas crear una instancia de <tt class="docutils literal"><span class="pre">Twig_SimpleTest</span></tt>:</p>
<div class="highlight-php"><div class="highlight"><pre><span class="nv">$twig</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">Twig_Environment</span><span class="p">(</span><span class="nv">$loader</span><span class="p">);</span>
<span class="nv">$test</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">Twig_SimpleTest</span><span class="p">(</span><span class="s1">&#39;test_name&#39;</span><span class="p">,</span> <span class="k">function</span> <span class="p">()</span> <span class="p">{</span>
<span class="c1">// ...</span>
<span class="p">});</span>
<span class="nv">$twig</span><span class="o">-&gt;</span><span class="na">addTest</span><span class="p">(</span><span class="nv">$test</span><span class="p">);</span>
</pre></div>
</div>
<p>Las pruebas no apoyan algunas opciones.</p>
</div>
<div class="section" id="etiquetas">
<h2>Etiquetas<a class="headerlink" href="#etiquetas" title="Enlazar permanentemente con este título">¶</a></h2>
<p>Una de las características más interesantes de un motor de plantillas como <em>Twig</em> es la posibilidad de definir nuevas construcciones del lenguaje. Esta también es la característica más compleja que necesitas comprender de cómo trabaja <em>Twig</em> internamente.</p>
<p>Vamos a crear una simple etiqueta <tt class="docutils literal"><span class="pre">set</span></tt> que te permita definir variables simples dentro de una plantilla. Puedes utilizar la etiqueta de la siguiente manera:</p>
<div class="highlight-jinja"><div class="highlight"><pre><span class="cp">{%</span> <span class="k">set</span> <span class="nv">name</span> <span class="o">=</span> <span class="s2">&quot;value&quot;</span> <span class="cp">%}</span><span class="x"></span>
<span class="cp">{{</span> <span class="nv">name</span> <span class="cp">}}</span><span class="x"></span>
<span class="c">{# debe producir value #}</span><span class="x"></span>
</pre></div>
</div>
<div class="admonition note">
<p class="first admonition-title">Nota</p>
<p class="last">La etiqueta <tt class="docutils literal"><span class="pre">set</span></tt> es parte de la extensión <tt class="docutils literal"><span class="pre">core</span></tt> y como tal siempre está disponible. La versión integrada es un poco más potente y de manera predeterminada es compatible con múltiples asignaciones (consulta el capítulo <a class="reference internal" href="templates.html"><em>Twig para diseñadores de plantillas</em></a> para más información).</p>
</div>
<p>para definir una nueva etiqueta son necesarios tres pasos:</p>
<ul class="simple">
<li>Definir una clase para analizar segmentos (responsable de analizar el código de la plantilla);</li>
<li>Definir una clase Nodo (responsable de convertir el código analizado a <em>PHP</em>);</li>
<li>Registrar la etiqueta.</li>
</ul>
<div class="section" id="registrando-una-nueva-etiqueta">
<h3>Registrando una nueva etiqueta<a class="headerlink" href="#registrando-una-nueva-etiqueta" title="Enlazar permanentemente con este título">¶</a></h3>
<p>Agregar una etiqueta es tan simple como una llamada al método <tt class="docutils literal"><span class="pre">addTokenParser</span></tt> en la instancia de <tt class="docutils literal"><span class="pre">Twig_Environment</span></tt>:</p>
<div class="highlight-php"><div class="highlight"><pre><span class="nv">$twig</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">Twig_Environment</span><span class="p">(</span><span class="nv">$loader</span><span class="p">);</span>
<span class="nv">$twig</span><span class="o">-&gt;</span><span class="na">addTokenParser</span><span class="p">(</span><span class="k">new</span> <span class="nx">Project_Set_TokenParser</span><span class="p">());</span>
</pre></div>
</div>
</div>
<div class="section" id="definiendo-un-analizador-de-fragmentos">
<h3>Definiendo un analizador de fragmentos<a class="headerlink" href="#definiendo-un-analizador-de-fragmentos" title="Enlazar permanentemente con este título">¶</a></h3>
<p>Ahora, vamos a ver el código real de esta clase:</p>
<div class="highlight-php"><div class="highlight"><pre><span class="k">class</span> <span class="nc">Project_Set_TokenParser</span> <span class="k">extends</span> <span class="nx">Twig_TokenParser</span>
<span class="p">{</span>
<span class="k">public</span> <span class="k">function</span> <span class="nf">parse</span><span class="p">(</span><span class="nx">Twig_Token</span> <span class="nv">$token</span><span class="p">)</span>
<span class="p">{</span>
<span class="nv">$lineno</span> <span class="o">=</span> <span class="nv">$token</span><span class="o">-&gt;</span><span class="na">getLine</span><span class="p">();</span>
<span class="nv">$name</span> <span class="o">=</span> <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">parser</span>
<span class="o">-&gt;</span><span class="na">getStream</span><span class="p">()</span>
<span class="o">-&gt;</span><span class="na">expect</span><span class="p">(</span><span class="nx">Twig_Token</span><span class="o">::</span><span class="na">NAME_TYPE</span><span class="p">)</span>
<span class="o">-&gt;</span><span class="na">getValue</span><span class="p">();</span>
<span class="nv">$this</span><span class="o">-&gt;</span><span class="na">parser</span><span class="o">-&gt;</span><span class="na">getExpressionParser</span><span class="p">()</span>
<span class="o">-&gt;</span><span class="na">expect</span><span class="p">(</span><span class="nx">Twig_Token</span><span class="o">::</span><span class="na">OPERATOR_TYPE</span><span class="p">,</span> <span class="s1">&#39;=&#39;</span><span class="p">);</span>
<span class="nv">$value</span> <span class="o">=</span> <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">parser</span>
<span class="o">-&gt;</span><span class="na">getExpressionParser</span><span class="p">()</span>
<span class="o">-&gt;</span><span class="na">parseExpression</span><span class="p">();</span>
<span class="nv">$this</span><span class="o">-&gt;</span><span class="na">parser</span><span class="o">-&gt;</span><span class="na">getStream</span><span class="p">()</span>
<span class="o">-&gt;</span><span class="na">expect</span><span class="p">(</span><span class="nx">Twig_Token</span><span class="o">::</span><span class="na">BLOCK_END_TYPE</span><span class="p">);</span>
<span class="k">return</span> <span class="k">new</span> <span class="nx">Project_Set_Node</span><span class="p">(</span> <span class="nv">$name</span><span class="p">,</span>
<span class="nv">$value</span><span class="p">,</span>
<span class="nv">$lineno</span><span class="p">,</span>
<span class="nv">$this</span><span class="o">-&gt;</span><span class="na">getTag</span><span class="p">()</span>
<span class="p">);</span>
<span class="p">}</span>
<span class="k">public</span> <span class="k">function</span> <span class="nf">getTag</span><span class="p">()</span>
<span class="p">{</span>
<span class="k">return</span> <span class="s1">&#39;set&#39;</span><span class="p">;</span>
<span class="p">}</span>
<span class="p">}</span>
</pre></div>
</div>
<p>El método <tt class="docutils literal"><span class="pre">getTag()</span></tt> debe devolver la etiqueta que queremos analizar, aquí <tt class="docutils literal"><span class="pre">set</span></tt>.</p>
<p>El método <tt class="docutils literal"><span class="pre">parse()</span></tt> se invoca cada vez que el analizador encuentra una etiqueta <tt class="docutils literal"><span class="pre">set</span></tt>. Este debe devolver una instancia de <tt class="docutils literal"><span class="pre">Twig_Node</span></tt> que representa el nodo (la llamada para la creación del <tt class="docutils literal"><span class="pre">Project_Set_Node</span></tt> se explica en la siguiente sección).</p>
<p>El proceso de análisis se simplifica gracias a un montón de métodos que se pueden llamar desde el fragmento del flujo (<tt class="docutils literal"><span class="pre">$this-&gt;parser-&gt;getStream()</span></tt>):</p>
<ul class="simple">
<li><tt class="docutils literal"><span class="pre">getCurrent()</span></tt>: Obtiene el segmento actual del flujo.</li>
<li><tt class="docutils literal"><span class="pre">next()</span></tt>: Mueve al siguiente segmento en la secuencia, <em>pero devuelve el antiguo</em>.</li>
<li><tt class="docutils literal"><span class="pre">test($type)</span></tt>, <tt class="docutils literal"><span class="pre">test($value)</span></tt> o <tt class="docutils literal"><span class="pre">test($type,</span> <span class="pre">$value)</span></tt>: Determina si el segmento actual es de un tipo o valor particular (o ambos). El valor puede ser un arreglo de varios posibles valores.</li>
<li><tt class="docutils literal"><span class="pre">expect($type[,</span> <span class="pre">$value[,</span> <span class="pre">$message]])</span></tt>: Si el segmento actual no es del tipo/valor dado lanza un error de sintaxis. De lo contrario, si el tipo y valor son correctos, devuelve el segmento y mueve el flujo al siguiente segmento.</li>
<li><tt class="docutils literal"><span class="pre">look()</span></tt>: Busca el siguiente segmento sin consumirlo.</li>
</ul>
<p>Las expresiones de análisis se llevan a cabo llamando a <tt class="docutils literal"><span class="pre">parseExpression()</span></tt> como lo hicimos para la etiqueta <tt class="docutils literal"><span class="pre">set</span></tt>.</p>
<div class="admonition tip">
<p class="first admonition-title">Truco</p>
<p class="last">Leer las clases <tt class="docutils literal"><span class="pre">TokenParser</span></tt> existentes es la mejor manera de aprender todos los detalles esenciales del proceso de análisis.</p>
</div>
</div>
<div class="section" id="definiendo-un-nodo">
<h3>Definiendo un nodo<a class="headerlink" href="#definiendo-un-nodo" title="Enlazar permanentemente con este título">¶</a></h3>
<p>La clase <tt class="docutils literal"><span class="pre">Project_Set_Node</span></tt> en sí misma es bastante simple:</p>
<div class="highlight-php"><div class="highlight"><pre><span class="k">class</span> <span class="nc">Project_Set_Node</span> <span class="k">extends</span> <span class="nx">Twig_Node</span>
<span class="p">{</span>
<span class="k">public</span> <span class="k">function</span> <span class="nf">__construct</span><span class="p">(</span> <span class="nv">$name</span><span class="p">,</span>
<span class="nx">Twig_Node_Expression</span> <span class="nv">$value</span><span class="p">,</span>
<span class="nv">$lineno</span><span class="p">,</span>
<span class="nv">$tag</span> <span class="o">=</span> <span class="k">null</span>
<span class="p">)</span>
<span class="p">{</span>
<span class="k">parent</span><span class="o">::</span><span class="na">__construct</span><span class="p">(</span> <span class="k">array</span><span class="p">(</span> <span class="s1">&#39;value&#39;</span> <span class="o">=&gt;</span> <span class="nv">$value</span> <span class="p">),</span>
<span class="k">array</span><span class="p">(</span> <span class="s1">&#39;name&#39;</span> <span class="o">=&gt;</span> <span class="nv">$name</span> <span class="p">),</span>
<span class="nv">$lineno</span><span class="p">,</span>
<span class="nv">$tag</span>
<span class="p">);</span>
<span class="p">}</span>
<span class="k">public</span> <span class="k">function</span> <span class="nf">compile</span><span class="p">(</span><span class="nx">Twig_Compiler</span> <span class="nv">$compiler</span><span class="p">)</span>
<span class="p">{</span>
<span class="nv">$compiler</span>
<span class="o">-&gt;</span><span class="na">addDebugInfo</span><span class="p">(</span><span class="nv">$this</span><span class="p">)</span>
<span class="o">-&gt;</span><span class="na">write</span><span class="p">(</span><span class="s1">&#39;$context[\&#39;&#39;</span><span class="o">.</span><span class="nv">$this</span><span class="o">-&gt;</span><span class="na">getAttribute</span><span class="p">(</span><span class="s1">&#39;name&#39;</span><span class="p">)</span><span class="o">.</span><span class="s1">&#39;\&#39;] = &#39;</span><span class="p">)</span>
<span class="o">-&gt;</span><span class="na">subcompile</span><span class="p">(</span><span class="nv">$this</span><span class="o">-&gt;</span><span class="na">getNode</span><span class="p">(</span><span class="s1">&#39;value&#39;</span><span class="p">))</span>
<span class="o">-&gt;</span><span class="na">raw</span><span class="p">(</span><span class="s2">&quot;;</span><span class="se">\n</span><span class="s2">&quot;</span><span class="p">)</span>
<span class="p">;</span>
<span class="p">}</span>
<span class="p">}</span>
</pre></div>
</div>
<p>El compilador implementa una interfaz fluida y proporciona métodos que ayudan a los desarrolladores a generar código <em>PHP</em> hermoso y fácil de leer:</p>
<ul class="simple">
<li><tt class="docutils literal"><span class="pre">subcompile()</span></tt>: Compila un nodo.</li>
<li><tt class="docutils literal"><span class="pre">raw()</span></tt>: Escribe tal cual la cadena dada.</li>
<li><tt class="docutils literal"><span class="pre">write()</span></tt>: Escribe la cadena dada añadiendo sangría al principio de cada línea.</li>
<li><tt class="docutils literal"><span class="pre">string()</span></tt>: Escribe una cadena entre comillas.</li>
<li><tt class="docutils literal"><span class="pre">repr()</span></tt>: Escribe una representación <em>PHP</em> de un valor dado (consulta <tt class="docutils literal"><span class="pre">Twig_Node_For</span></tt> para un ejemplo real).</li>
<li><tt class="docutils literal"><span class="pre">addDebugInfo()</span></tt>: Agrega como comentario la línea del archivo de plantilla original relacionado con el nodo actual.</li>
<li><tt class="docutils literal"><span class="pre">indent()</span></tt>: Aplica sangrías al código generado (consulta <tt class="docutils literal"><span class="pre">Twig_Node_Block</span></tt> para un ejemplo real).</li>
<li><tt class="docutils literal"><span class="pre">outdent()</span></tt>: Quita la sangría al código generado (consulta <tt class="docutils literal"><span class="pre">Twig_Node_Block</span></tt> para un ejemplo real).</li>
</ul>
</div>
</div>
<div class="section" id="creando-una-extension">
<span id="creating-extensions"></span><h2>Creando una extensión<a class="headerlink" href="#creando-una-extension" title="Enlazar permanentemente con este título">¶</a></h2>
<p>La principal motivación para escribir una extensión es mover el código usado frecuentemente a una clase reutilizable como agregar apoyo para la internacionalización. Una extensión puede definir etiquetas, filtros, pruebas, operadores, variables globales, funciones y visitantes de nodo.</p>
<p>La creación de una extensión también hace una mejor separación del código que se ejecuta en tiempo de compilación y el código necesario en tiempo de ejecución. Por lo tanto, hace que tu código sea más rápido.</p>
<p>La mayoría de las veces, es útil crear una extensión para tu proyecto, para acoger todas las etiquetas y filtros específicos que deseas agregar a <em>Twig</em>.</p>
<div class="admonition tip">
<p class="first admonition-title">Truco</p>
<p class="last">Al empacar tu código en una extensión, <em>Twig</em> es lo suficientemente inteligente como para volver a compilar tus plantillas cada vez que les hagas algún cambio (cuando <tt class="docutils literal"><span class="pre">auto_reload</span></tt> está habilitado).</p>
</div>
<div class="admonition note">
<p class="first admonition-title">Nota</p>
<p class="last">Antes de escribir tus propias extensiones, échale un vistazo al repositorio de extensiones oficial de <em>Twig</em>: <a class="reference external" href="http://github.com/fabpot/Twig-extensions">http://github.com/fabpot/Twig-extensions</a>.</p>
</div>
<p>Una extensión es una clase que implementa la siguiente interfaz:</p>
<div class="highlight-php"><div class="highlight"><pre><span class="k">interface</span> <span class="nx">Twig_ExtensionInterface</span>
<span class="p">{</span>
<span class="sd">/**</span>
<span class="sd"> * Inicia el entorno en tiempo de ejecución.</span>
<span class="sd"> *</span>
<span class="sd"> * Aquí es donde puedes cargar algún archivo que contenga funciones</span>
<span class="sd"> * de filtro, por ejemplo.</span>
<span class="sd"> *</span>
<span class="sd"> * @param Twig_Environment $environment La instancia actual de</span>
<span class="sd"> * Twig_Environment</span>
<span class="sd"> */</span>
<span class="k">function</span> <span class="nf">initRuntime</span><span class="p">(</span><span class="nx">Twig_Environment</span> <span class="nv">$environment</span><span class="p">);</span>
<span class="sd">/**</span>
<span class="sd"> * Devuelve instancias del analizador de segmentos para añadirlos a</span>
<span class="sd"> * la lista existente.</span>
<span class="sd"> *</span>
<span class="sd"> * @return array Un arreglo de instancias Twig_TokenParserInterface</span>
<span class="sd"> * o Twig_TokenParserBrokerInterface</span>
<span class="sd"> */</span>
<span class="k">function</span> <span class="nf">getTokenParsers</span><span class="p">();</span>
<span class="sd">/**</span>
<span class="sd"> * Devuelve instancias del visitante de nodos para añadirlas a la</span>
<span class="sd"> * lista existente.</span>
<span class="sd"> *</span>
<span class="sd"> * @return array Un arreglo de instancias de</span>
<span class="sd"> * Twig_NodeVisitorInterface</span>
<span class="sd"> */</span>
<span class="k">function</span> <span class="nf">getNodeVisitors</span><span class="p">();</span>
<span class="sd">/**</span>
<span class="sd"> * Devuelve una lista de filtros para añadirla a la lista</span>
<span class="sd"> * existente.</span>
<span class="sd"> *</span>
<span class="sd"> * @return array Un arreglo de filtros</span>
<span class="sd"> */</span>
<span class="k">function</span> <span class="nf">getFilters</span><span class="p">();</span>
<span class="sd">/**</span>
<span class="sd"> * Devuelve una lista de pruebas para añadirla a la lista</span>
<span class="sd"> * existente.</span>
<span class="sd"> *</span>
<span class="sd"> * @return array Un arreglo de pruebas</span>
<span class="sd"> */</span>
<span class="k">function</span> <span class="nf">getTests</span><span class="p">();</span>
<span class="sd">/**</span>
<span class="sd"> * Devuelve una lista de funciones para añadirla a la lista</span>
<span class="sd"> * existente.</span>
<span class="sd"> *</span>
<span class="sd"> * @return array Un arreglo de funciones</span>
<span class="sd"> */</span>
<span class="k">function</span> <span class="nf">getFunctions</span><span class="p">();</span>
<span class="sd">/**</span>
<span class="sd"> * Devuelve una lista de operadores para añadirla a la lista</span>
<span class="sd"> * existente.</span>
<span class="sd"> *</span>
<span class="sd"> * @return array Un arreglo de operadores</span>
<span class="sd"> */</span>
<span class="k">function</span> <span class="nf">getOperators</span><span class="p">();</span>
<span class="sd">/**</span>
<span class="sd"> * Devuelve una lista de variables globales para añadirla a la</span>
<span class="sd"> * lista existente.</span>
<span class="sd"> *</span>
<span class="sd"> * @return array Un arreglo de variables globales</span>
<span class="sd"> */</span>
<span class="k">function</span> <span class="nf">getGlobals</span><span class="p">();</span>
<span class="sd">/**</span>
<span class="sd"> * Devuelve el nombre de la extensión.</span>
<span class="sd"> *</span>
<span class="sd"> * @return string El nombre de la extensión</span>
<span class="sd"> */</span>
<span class="k">function</span> <span class="nf">getName</span><span class="p">();</span>
<span class="p">}</span>
</pre></div>
</div>
<p>Para mantener tu clase de extensión limpia y ordenada, puedes heredar de la clase <tt class="docutils literal"><span class="pre">Twig_Extension</span></tt> incorporada en lugar de implementar toda la interfaz. De esta forma, sólo tienes que implementar el método <tt class="docutils literal"><span class="pre">getName()</span></tt> como el que proporcionan las implementaciones vacías de <tt class="docutils literal"><span class="pre">Twig_Extension</span></tt> para todos los otros métodos.</p>
<p>El método <tt class="docutils literal"><span class="pre">getName()</span></tt> debe devolver un identificador único para tu extensión.</p>
<p>Ahora, con esta información en mente, vamos a crear la extensión más básica posible:</p>
<div class="highlight-php"><div class="highlight"><pre><span class="k">class</span> <span class="nc">Project_Twig_Extension</span> <span class="k">extends</span> <span class="nx">Twig_Extension</span>
<span class="p">{</span>
<span class="k">public</span> <span class="k">function</span> <span class="nf">getName</span><span class="p">()</span>
<span class="p">{</span>
<span class="k">return</span> <span class="s1">&#39;project&#39;</span><span class="p">;</span>
<span class="p">}</span>
<span class="p">}</span>
</pre></div>
</div>
<div class="admonition note">
<p class="first admonition-title">Nota</p>
<p class="last">Por supuesto, esta extensión no hace nada por ahora. Vamos a personalizarla en las siguientes secciones.</p>
</div>
<p>A <em>Twig</em> no le importa dónde guardas tu extensión en el sistema de archivos, puesto que todas las extensiones se deben registrar explícitamente para estar disponibles en tus plantillas.</p>
<p>Puedes registrar una extensión con el método <tt class="docutils literal"><span class="pre">addExtension()</span></tt> en tu objeto <tt class="docutils literal"><span class="pre">Environment</span></tt> principal:</p>
<div class="highlight-php"><div class="highlight"><pre><span class="nv">$twig</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">Twig_Environment</span><span class="p">(</span><span class="nv">$loader</span><span class="p">);</span>
<span class="nv">$twig</span><span class="o">-&gt;</span><span class="na">addExtension</span><span class="p">(</span><span class="k">new</span> <span class="nx">Project_Twig_Extension</span><span class="p">());</span>
</pre></div>
</div>
<p>Por supuesto, tienes que cargar primero el archivo de la extensión, ya sea utilizando <tt class="docutils literal"><span class="pre">require_once()</span></tt> o con un cargador automático (consulta la sección <a class="reference external" href="http://www.php.net/spl_autoload_register">spl_autoload_register()</a>).</p>
<div class="admonition tip">
<p class="first admonition-title">Truco</p>
<p class="last">Las extensiones integradas son grandes ejemplos de cómo trabajan las extensiones.</p>
</div>
<div class="section" id="id1">
<h3>Globales<a class="headerlink" href="#id1" title="Enlazar permanentemente con este título">¶</a></h3>
<p>Puedes registrar las variables globales en una extensión vía el método <tt class="docutils literal"><span class="pre">getGlobals()</span></tt>:</p>
<div class="highlight-php"><div class="highlight"><pre><span class="k">class</span> <span class="nc">Project_Twig_Extension</span> <span class="k">extends</span> <span class="nx">Twig_Extension</span>
<span class="p">{</span>
<span class="k">public</span> <span class="k">function</span> <span class="nf">getGlobals</span><span class="p">()</span>
<span class="p">{</span>
<span class="k">return</span> <span class="k">array</span><span class="p">(</span>
<span class="s1">&#39;text&#39;</span> <span class="o">=&gt;</span> <span class="k">new</span> <span class="nx">Text</span><span class="p">(),</span>
<span class="p">);</span>
<span class="p">}</span>
<span class="c1">// ...</span>
<span class="p">}</span>
</pre></div>
</div>
</div>
<div class="section" id="id2">
<h3>Funciones<a class="headerlink" href="#id2" title="Enlazar permanentemente con este título">¶</a></h3>
<p>Puedes registrar funciones en una extensión vía el método <tt class="docutils literal"><span class="pre">getFunctions()</span></tt>:</p>
<div class="highlight-php"><div class="highlight"><pre><span class="k">class</span> <span class="nc">Project_Twig_Extension</span> <span class="k">extends</span> <span class="nx">Twig_Extension</span>
<span class="p">{</span>
<span class="k">public</span> <span class="k">function</span> <span class="nf">getFunctions</span><span class="p">()</span>
<span class="p">{</span>
<span class="k">return</span> <span class="k">array</span><span class="p">(</span>
<span class="k">new</span> <span class="nx">Twig_SimpleFunction</span><span class="p">(</span><span class="s1">&#39;lipsum&#39;</span><span class="p">,</span> <span class="s1">&#39;generate_lipsum&#39;</span><span class="p">),</span>
<span class="p">);</span>
<span class="p">}</span>
<span class="c1">// ...</span>
<span class="p">}</span>
</pre></div>
</div>
</div>
<div class="section" id="id3">
<h3>Filtros<a class="headerlink" href="#id3" title="Enlazar permanentemente con este título">¶</a></h3>
<p>Para agregar un filtro a una extensión, es necesario sustituir el método <tt class="docutils literal"><span class="pre">getFilters()</span></tt>. Este método debe devolver un arreglo de filtros para añadir al entorno <em>Twig</em>:</p>
<div class="highlight-php"><div class="highlight"><pre><span class="k">class</span> <span class="nc">Project_Twig_Extension</span> <span class="k">extends</span> <span class="nx">Twig_Extension</span>
<span class="p">{</span>
<span class="k">public</span> <span class="k">function</span> <span class="nf">getFilters</span><span class="p">()</span>
<span class="p">{</span>
<span class="k">return</span> <span class="k">array</span><span class="p">(</span>
<span class="k">new</span> <span class="nx">Twig_SimpleFilter</span><span class="p">(</span><span class="s1">&#39;rot13&#39;</span><span class="p">,</span> <span class="s1">&#39;str_rot13&#39;</span><span class="p">),</span>
<span class="p">);</span>
<span class="p">}</span>
<span class="c1">// ...</span>
<span class="p">}</span>
</pre></div>
</div>
</div>
<div class="section" id="id4">
<h3>Etiquetas<a class="headerlink" href="#id4" title="Enlazar permanentemente con este título">¶</a></h3>
<p>Puedes agregar una etiqueta en una extensión reemplazando el método <tt class="docutils literal"><span class="pre">getTokenParsers()</span></tt>. Este método debe devolver un arreglo de etiquetas para añadir al entorno <em>Twig</em>:</p>
<div class="highlight-php"><div class="highlight"><pre><span class="k">class</span> <span class="nc">Project_Twig_Extension</span> <span class="k">extends</span> <span class="nx">Twig_Extension</span>
<span class="p">{</span>
<span class="k">public</span> <span class="k">function</span> <span class="nf">getTokenParsers</span><span class="p">()</span>
<span class="p">{</span>
<span class="k">return</span> <span class="k">array</span><span class="p">(</span><span class="k">new</span> <span class="nx">Project_Set_TokenParser</span><span class="p">());</span>
<span class="p">}</span>
<span class="c1">// ...</span>
<span class="p">}</span>
</pre></div>
</div>
<p>En el código anterior, hemos añadido una sola etiqueta nueva, definida por la clase <tt class="docutils literal"><span class="pre">Project_Set_TokenParser</span></tt>. La clase <tt class="docutils literal"><span class="pre">Project_Set_TokenParser</span></tt> es responsable de analizar la etiqueta y compilarla a <em>PHP</em>.</p>
</div>
<div class="section" id="operadores">
<h3>Operadores<a class="headerlink" href="#operadores" title="Enlazar permanentemente con este título">¶</a></h3>
<p>El método <tt class="docutils literal"><span class="pre">getOperators()</span></tt> te permite añadir nuevos operadores. Aquí tienes cómo añadir los operadores
<tt class="docutils literal"><span class="pre">!</span></tt>, <tt class="docutils literal"><span class="pre">||</span></tt> y <tt class="docutils literal"><span class="pre">&amp;&amp;</span></tt>:</p>
<div class="highlight-php"><div class="highlight"><pre><span class="k">class</span> <span class="nc">Project_Twig_Extension</span> <span class="k">extends</span> <span class="nx">Twig_Extension</span>
<span class="p">{</span>
<span class="k">public</span> <span class="k">function</span> <span class="nf">getOperators</span><span class="p">()</span>
<span class="p">{</span>
<span class="k">return</span> <span class="k">array</span><span class="p">(</span>
<span class="k">array</span><span class="p">(</span>
<span class="s1">&#39;!&#39;</span> <span class="o">=&gt;</span> <span class="k">array</span><span class="p">(</span> <span class="s1">&#39;precedence&#39;</span> <span class="o">=&gt;</span> <span class="mi">50</span><span class="p">,</span>
<span class="s1">&#39;class&#39;</span>
<span class="o">=&gt;</span> <span class="s1">&#39;Twig_Node_Expression_Unary_Not&#39;</span>
<span class="p">),</span>
<span class="p">),</span>
<span class="k">array</span><span class="p">(</span>
<span class="s1">&#39;||&#39;</span> <span class="o">=&gt;</span> <span class="k">array</span><span class="p">(</span> <span class="s1">&#39;precedence&#39;</span> <span class="o">=&gt;</span> <span class="mi">10</span><span class="p">,</span>
<span class="s1">&#39;class&#39;</span>
<span class="o">=&gt;</span> <span class="s1">&#39;Twig_Node_Expression_Binary_Or&#39;</span><span class="p">,</span>
<span class="s1">&#39;associativity&#39;</span>
<span class="o">=&gt;</span> <span class="nx">Twig_ExpressionParser</span><span class="o">::</span><span class="na">OPERATOR_LEFT</span>
<span class="p">),</span>
<span class="s1">&#39;&amp;&amp;&#39;</span> <span class="o">=&gt;</span> <span class="k">array</span><span class="p">(</span> <span class="s1">&#39;precedence&#39;</span> <span class="o">=&gt;</span> <span class="mi">15</span><span class="p">,</span>
<span class="s1">&#39;class&#39;</span>
<span class="o">=&gt;</span> <span class="s1">&#39;Twig_Node_Expression_Binary_And&#39;</span><span class="p">,</span>
<span class="s1">&#39;associativity&#39;</span>
<span class="o">=&gt;</span> <span class="nx">Twig_ExpressionParser</span><span class="o">::</span><span class="na">OPERATOR_LEFT</span>
<span class="p">),</span>
<span class="p">),</span>
<span class="p">);</span>
<span class="p">}</span>
<span class="c1">// ...</span>
<span class="p">}</span>
</pre></div>
</div>
</div>
<div class="section" id="id5">
<h3>Pruebas<a class="headerlink" href="#id5" title="Enlazar permanentemente con este título">¶</a></h3>
<p>El método <tt class="docutils literal"><span class="pre">getTests()</span></tt> te permite añadir funciones de prueba:</p>
<div class="highlight-php"><div class="highlight"><pre><span class="k">class</span> <span class="nc">Project_Twig_Extension</span> <span class="k">extends</span> <span class="nx">Twig_Extension</span>
<span class="p">{</span>
<span class="k">public</span> <span class="k">function</span> <span class="nf">getTests</span><span class="p">()</span>
<span class="p">{</span>
<span class="k">return</span> <span class="k">array</span><span class="p">(</span>
<span class="k">new</span> <span class="nx">Twig_SimpleTest</span><span class="p">(</span><span class="s1">&#39;even&#39;</span><span class="p">,</span> <span class="s1">&#39;twig_test_even&#39;</span><span class="p">),</span>
<span class="p">);</span>
<span class="p">}</span>
<span class="c1">// ...</span>
<span class="p">}</span>
</pre></div>
</div>
</div>
</div>
<div class="section" id="sobrecargando">
<h2>Sobrecargando<a class="headerlink" href="#sobrecargando" title="Enlazar permanentemente con este título">¶</a></h2>
<p>Para sobrecargar un filtro, prueba, operador, variable global o función existente,
defínelo de nuevo <strong>tan tarde como sea posible</strong>:</p>
<div class="highlight-php"><div class="highlight"><pre><span class="nv">$twig</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">Twig_Environment</span><span class="p">(</span><span class="nv">$loader</span><span class="p">);</span>
<span class="nv">$twig</span><span class="o">-&gt;</span><span class="na">addFilter</span><span class="p">(</span><span class="k">new</span> <span class="nx">Twig_SimpleFilter</span><span class="p">(</span><span class="s1">&#39;date&#39;</span><span class="p">,</span> <span class="k">function</span> <span class="p">(</span><span class="nv">$timestamp</span><span class="p">,</span> <span class="nv">$format</span> <span class="o">=</span> <span class="s1">&#39;F j, Y H:i&#39;</span><span class="p">)</span> <span class="p">{</span>
<span class="c1">// hace algo diferente que el filtro date integrado</span>
<span class="p">}));</span>
</pre></div>
</div>
<p>Aquí, se sobrecargó el filtro <tt class="docutils literal"><span class="pre">date</span></tt> integrado con uno personalizado.</p>
<p>Esto también trabaja con una extensión:</p>
<div class="highlight-php"><div class="highlight"><pre><span class="k">class</span> <span class="nc">MyCoreExtension</span> <span class="k">extends</span> <span class="nx">Twig_Extension</span>
<span class="p">{</span>
<span class="k">public</span> <span class="k">function</span> <span class="nf">getFilters</span><span class="p">()</span>
<span class="p">{</span>
<span class="k">return</span> <span class="k">array</span><span class="p">(</span>
<span class="k">new</span> <span class="nx">Twig_SimpleFilter</span><span class="p">(</span><span class="s1">&#39;date&#39;</span><span class="p">,</span> <span class="k">array</span><span class="p">(</span><span class="nv">$this</span><span class="p">,</span> <span class="s1">&#39;dateFilter&#39;</span><span class="p">)),</span>
<span class="p">);</span>
<span class="p">}</span>
<span class="k">public</span> <span class="k">function</span> <span class="nf">dateFilter</span><span class="p">(</span><span class="nv">$timestamp</span><span class="p">,</span> <span class="nv">$format</span> <span class="o">=</span> <span class="s1">&#39;F j, Y H:i&#39;</span><span class="p">)</span>
<span class="p">{</span>
<span class="c1">// hace algo diferente que el filtro date integrado</span>
<span class="p">}</span>
<span class="k">public</span> <span class="k">function</span> <span class="nf">getName</span><span class="p">()</span>
<span class="p">{</span>
<span class="k">return</span> <span class="s1">&#39;project&#39;</span><span class="p">;</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="nv">$twig</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">Twig_Environment</span><span class="p">(</span><span class="nv">$loader</span><span class="p">);</span>
<span class="nv">$twig</span><span class="o">-&gt;</span><span class="na">addExtension</span><span class="p">(</span><span class="k">new</span> <span class="nx">MyCoreExtension</span><span class="p">());</span>
</pre></div>
</div>
<div class="admonition caution">
<p class="first admonition-title">Prudencia</p>
<p class="last">Ten en cuenta que no es recomendable sobrecargar elementos integrados en <em>Twig</em> puesto que puede ser confuso.</p>
</div>
</div>
<div class="section" id="probando-una-extension">
<h2>Probando una extensión<a class="headerlink" href="#probando-una-extension" title="Enlazar permanentemente con este título">¶</a></h2>
<div class="section" id="pruebas-funcionales">
<h3>Pruebas funcionales<a class="headerlink" href="#pruebas-funcionales" title="Enlazar permanentemente con este título">¶</a></h3>
<p>Puedes crear pruebas funcionales para extensiones simplemente creando la siguiente estructura de archivos en tu directorio de pruebas (<tt class="file docutils literal"><span class="pre">test</span></tt>):</p>
<div class="highlight-php"><div class="highlight"><pre><span class="nx">Fixtures</span><span class="o">/</span>
<span class="nx">filters</span><span class="o">/</span>
<span class="nx">foo</span><span class="o">.</span><span class="nx">test</span>
<span class="nx">bar</span><span class="o">.</span><span class="nx">test</span>
<span class="nx">functions</span><span class="o">/</span>
<span class="nx">foo</span><span class="o">.</span><span class="nx">test</span>
<span class="nx">bar</span><span class="o">.</span><span class="nx">test</span>
<span class="nx">tags</span><span class="o">/</span>
<span class="nx">foo</span><span class="o">.</span><span class="nx">test</span>
<span class="nx">bar</span><span class="o">.</span><span class="nx">test</span>
<span class="nx">IntegrationTest</span><span class="o">.</span><span class="nx">php</span>
</pre></div>
</div>
<p>El archivo <tt class="file docutils literal"><span class="pre">IntegrationTest.php</span></tt> debe tener la siguiente apariencia:</p>
<div class="highlight-php"><div class="highlight"><pre><span class="k">class</span> <span class="nc">Project_Tests_IntegrationTest</span> <span class="k">extends</span> <span class="nx">Twig_Test_IntegrationTestCase</span>
<span class="p">{</span>
<span class="k">public</span> <span class="k">function</span> <span class="nf">getExtensions</span><span class="p">()</span>
<span class="p">{</span>
<span class="k">return</span> <span class="k">array</span><span class="p">(</span>
<span class="k">new</span> <span class="nx">Project_Twig_Extension1</span><span class="p">(),</span>
<span class="k">new</span> <span class="nx">Project_Twig_Extension2</span><span class="p">(),</span>
<span class="p">);</span>
<span class="p">}</span>
<span class="k">public</span> <span class="k">function</span> <span class="nf">getFixturesDir</span><span class="p">()</span>
<span class="p">{</span>
<span class="k">return</span> <span class="nb">dirname</span><span class="p">(</span><span class="k">__FILE__</span><span class="p">)</span><span class="o">.</span><span class="s1">&#39;/Fixtures/&#39;</span><span class="p">;</span>
<span class="p">}</span>
<span class="p">}</span>
</pre></div>
</div>
<p>Los accesorios de ejemplo se pueden encontrar dentro del directorio del repositorio de <em>Twig</em> <a class="reference external" href="https://github.com/fabpot/Twig/tree/master/test/Twig/Tests/Fixtures">tests/Twig/Fixtures</a>.</p>
</div>
<div class="section" id="pruebas-de-nodo">
<h3>Pruebas de nodo<a class="headerlink" href="#pruebas-de-nodo" title="Enlazar permanentemente con este título">¶</a></h3>
<p>Probar los visitantes de nodo puede ser complejo, así que extiende tus casos de prueba de <tt class="docutils literal"><span class="pre">Twig_Test_NodeTestCase</span></tt>. Puedes encontrar ejemplos en el directorio del repositorio de <em>Twig</em> <a class="reference external" href="https://github.com/fabpot/Twig/tree/master/test/Twig/Tests/Node">tests/Twig/Node</a>.</p>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="clearer"></div>
</div>
<a href="https://github.com/fabpot/Twig"><img style="position: fixed; top: 0; right: 0; border: 0;" src="http://gitnacho.github.com/tnp/img/comun/bifurcame.png" alt="Bifúrcame en GitHub" /></a>
<div style="width:740px;margin:10px auto;">
<div class="related">
<h3>Navegación</h3>
<ul>
<li class="right" style="margin-right: 10px">
<a href="genindex.html" title="Índice General"
>índice</a></li>
<li class="right" >
<a href="internals.html" title="Twig por dentro"
>siguiente</a> |</li>
<li class="right" >
<a href="api.html" title="Twig para desarrolladores"
>anterior</a> |</li>
<li><a href="index.html">Twig en Español</a> &raquo;</li>
</ul>
</div>
</div>
<div style="width: 740px; margin: 0 auto;">
<div id="disqus_thread"></div>
<div class="footer">
&copy; Copyright 2011-2013, Traducido por Nacho Pacheco.
Actualizado por última vez en Jan 18, 2013.
Creado con <a href="http://sphinx.pocoo.org/">Sphinx</a> 1.1.3.
</div>
</div>
<script type="text/javascript">
var disqus_shortname = 'documentos-mx';
var disqus_developer = 1;
(function() {
var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true;
dsq.src = 'http://' + disqus_shortname + '.disqus.com/embed.js';
(document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq);
})();
</script>
<noscript>
Por favor activa JavaScript para ver los <a href="http://disqus.com/?ref_noscript">comentarios accionados por Disqus.</a>
</noscript>
</body>
</html>
Jump to Line
Something went wrong with that request. Please try again.