Giter Site home page Giter Site logo

twigphp / twig Goto Github PK

View Code? Open in Web Editor NEW
8.1K 8.1K 1.2K 10.24 MB

Twig, the flexible, fast, and secure template language for PHP

Home Page: https://twig.symfony.com/

License: BSD 3-Clause "New" or "Revised" License

PHP 99.71% HTML 0.03% Shell 0.19% Twig 0.07%
php template-engine template-language templating twig

twig's People

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

twig's Issues

Marking filters as escape-safe

Hello,

I wrote a custom filter that, in addition to doing the basic htmlspecialchars() type conversion, converts any \n to
. I named the filter "custom_br".

I'm using the autoescape functionality, and I'm pondering whether it was a good idea that certain filters could be marked as "escape-safe".

That is: currently I have to write in the template:

{{ myVariable|custom_br|safe }}

I feel that the "|safe" part is kind of unneeded, or somehow "wrong".

Comments?

Implementation:

Currently the getFilters() hook returns an array of filters like this:

return array(
'custom_br' => array('my_function_name', false)
);

I suggest an alternative syntax:

return array(
'custom_br' => array(
'function' => 'my_function_name' # required
'safe' => true, # optional
'passEnv' => false, # optional
)
)
);

This would allow adding further features, such as a 'deterministic' => true for adding performance.

AFAIK:

  • this change could be made backward-compatible (the old syntax would be deprecated).
  • this change would not affect runtime performance

Create New Tag Extended Tutorial Needed

Hello Twig team,
This is not a bug actually.
I'm trying to make my own tag and parse it, but got some troubles.

Tag "hkfield" looks something like this:

{% hkfield name render "form" class "inp-black" style "width:120px" %}

where "name" is the object passed to template, all other string is key=>value pairs of parameters.
i.e. render="form"

There are can be some variable count of any type of parameters.

I try to parse them something like this

class HkFieldTokenParser extends Twig_TokenParser
{
public function parse(Twig_Token $token)
{
$lineno = $token->getLine();

    $stream = $this->parser->getStream();

    $name = $stream->expect(Twig_Token::NAME_TYPE)->getValue();

    $params = array();
    $paramName = null;

    while (!$stream->isEOF())
    {
        $token = $stream->next();
        if ($token->getType()==Twig_Token::NAME_TYPE)
        {
            $paramName = $token->getValue();
            $params[$paramName] = null;
        }

        if ($token->getType()==Twig_Token::STRING_TYPE)
        {
            $params[$paramName] = $token->getValue();
        }
    }

    unset($params['name']);

    return new HkFieldNode($name, $params, $lineno, $this->getTag());
}

public function getTag()
{
    return 'hkfield';
}

}

The problem is: my object "name" renders correctly, but all the content of template which goes after my custom tag is missing.
Please help me understand the twig logic.

Allow macro calls to call other variables (and not output directly, but return instead)

Hi,

We've just come up with a use case where we may want to be able to treat macros like any other variable (which is what they are) and nest a call to another macro from within a macro call itself, and have the output returned for use in the other macro.

An example if this would be:
{% macro row(label, content) %}

{{ label }}


{{ content|safe }}

{% endmacro %}

{% macro input(name, type, value) %}
    <input type="{{ type }}" name="{{ name }}" value="{{ value }}" />
{% endmacro %}

{% import "test.tpl" as form %}

{{ form.row(
    'Label',
    form.input('test', 'text', 'Value')
) }}

The problem is, this isn't possible at the moment for a few reasons:

  • Macros output directly (echo) instead of return a value.
  • This seems to be how they avoid being passed through escapers, because they don't return anything so when the above is changed, the macro content becomes escaped.

I've just committed a change to my fork that allows the above to work, and also means that macros aren't passed through the escaper. Commit is here: http://github.com/chrisboulton/Twig/commit/4183bcc64c766c46fdeb2fe871c4cea50e0d32da

Any interest in pulling this in to the official releases?

There's a few things I don't like about what I've done - specifically the need to use ob_start() and ob_get_clean() to fetch the content of the macros - so improvements on that are welcome.

Macro autoescaping

Variables passed to macros are not automaticaly escaped, but autoescape is turned on

[feature] Extend Twig_Node_Set with customizable $context variable

Node_Set could be used within custom nodes but it necessary to have an ability to specify a variable name results will be assigned to. For now it is hard coded as '$context'. The idea is to extend the class with a new method setVarName():

--- a/lib/Twig/Node/Set.php     Wed Feb 17 15:18:58 2010 +0300
+++ b/lib/Twig/Node/Set.php     Wed Feb 17 17:03:18 2010 +0300
@@ -5,6 +5,7 @@
   protected $names;
   protected $values;
   protected $isMultitarget;
+  protected $var_name = '$context';

   public function __construct($isMultitarget, $names, $values, $lineno, $tag = null)
   {
@@ -15,6 +16,12 @@
     $this->values = $values;
   }

+  public function setVarName($var_name) {
+      $this->var_name = $var_name;
+
+      return $this;
+  }
+
   public function __toString()
   {
     $repr = array(get_class($this).'('.($this->isMultitarget ? implode(', ', $this->names) : $this->names).',');
@@ -62,7 +69,8 @@
         }

         $compiler
-          ->raw('$context[')
+          ->raw($this->var_name)
+          ->raw('[')
           ->string($node->getName())
           ->raw(']')
         ;
@@ -72,7 +80,8 @@
     else
     {
       $compiler
-        ->write('$context[')
+        ->write($this->var_name)
+        ->write('[')
         ->string($this->names->getName())
         ->raw(']')
       ;

rand in Node_For

I propose replace
$var = rand(1, 999999);
with
static $i = 0;
$var = $i++;

Dynamic inheritance

It would be great if expressions can be used within {% extends %} tag like in {% include %}
Example:

{% extends basePath ~ modulePath ~ 'my.html' %}

twig_length_filter is not utf8 safe

As twig_length_filter uses strlen for strings it returns wrong values for strings in utf8 encoding.
I propose to implement it in this way:

function twig_length_filter($aValue) {
return is_string($aValue) ? mb_strlen($aValue, mb_detect_encoding($aValue)) : count($aValue);
}

Probably checks for multibyte support should be added.

Closures support

Now there is no support for calling closures. Call to 1st-level closure {{ closure('test') }} causes syntax error, call 2nd-level (and more) closure {{ some.closure('test') }} causes php error (can't convert closure to string)

Object properties

How do you access object properties (public or via __get method)?

plus operator does not concatenate strings

The Twig documentation mentions:

+: Adds two objects together. Usually the objects are numbers but if both are strings or lists you can concatenate them this way. This however is not the preferred way to concatenate strings! For string concatenation have a look at the ~ operator. {{ 1 + 1 }} is 2.

However, the following code:
{{ 'hello' + 'world' }}

Produces:

0

So instead, the ~ operator must be used:
{{ 'hello' ~ 'world' }}

Which results in the expected:

helloworld

Since using a plus with PHP's mixed types is kind of messy, I would suggest dropping it for concatenation and using the ~ operator instead, and adjusting that in the docs.

I have not researched why it's not working as advertised.

Add 'loop.parity' for zebra row coloring

Hello,

it's very common that one wants to color even and odd rows of a list/table/etc. with alternative colors. That's why I'm suggesting a shortcut variable 'loop.parity' that yields 'even' or 'odd'. It could be used like this:

  <tr class="{{ loop.parity }}">...</tr>

Very readable, and it also makes the css code more readable.

Here's a patch:

*** Twig.orig/Node/For.php  Wed Mar 17 21:39:34 2010
--- Twig/Node/For.php   Thu Mar 18 02:17:57 2010
***************
*** 90,95 ****
--- 90,96 ----
          ->write("  'revindex'  => \$length,\n")
          ->write("  'first'     => true,\n")
          ->write("  'last'      => 1 === \$length,\n")
+         ->write("  'parity'    => 'odd',\n")
          ->write(");\n")
        ;
      }
***************
*** 120,125 ****
--- 121,127 ----
          ->write("--\$context['loop']['revindex'];\n")
          ->write("\$context['loop']['first'] = false;\n")
          ->write("\$context['loop']['last'] = 0 === \$context['loop']['revindex0'];\n")
+         ->write("\$context['loop']['parity'] = (\$context['loop']['parity']==='even'?'odd':'even');\n")
        ;
      }

nl2br filter

I am missing the nl2br filter
'nl2br' => new Twig_Filter_Function('nl2br'),[/code]

For loop context

When you do something like that :
{% for i in 1..nbLine %}


{% for j in 0..4 %}
{{k}}
{% set k as k+1 %}
{% endfor %}

{% endfor %}
It display :
0 1 2 3 4
0 1 2 3 4
whereas
0 1 2 3 4
5 6 7 8 9
is expected.

The "k" variable get back to 0 a the end of the second loop. Maybe not a bug , but the fact that it gets the context as it was before the loop began is not very convenient.

http://groups.google.com/group/twig-users/browse_thread/thread/f0fe0940519519d

Smarter trim_blocks?

Is there any possibility of seeing a smarter trim_blocks?

For example, here is some output while using trim_blocks and my interpretation of what would be preferred.

<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">

    {% if test %}<title>Test conditional.</title>{% endif %}
</head>

<body>

trim_blocks output:

<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">

    </head>

<body>

or:

<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">

    <title>Test conditional.</title></head>

<body>

prefered:

<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
</head>

<body>

or:

<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">

    <title>Test conditional.</title>
</head>

<body>

It processes things a bit worse when you're using tags in a block format rather than inline.

Maybe the addition of a pretty environment option that behaves like above if trim_blocks is still wanted to mimic PHP's behavior?

Calling doctrine methods - case-sensitivity problem

Hi,

Page:
  columns:...
  relations:
    Category:         { class: Category, foreignAlias: Pages, onDelete: CASCADE }

and then

{% for page in category.pages %}

Twig will not call category->getPages(), it checks whether exist function category->getpages() ... its ok in php but Doctrine itself seems case sensitive and it will not work. If i try category.Pages instead, it will end up with same result (is there somewhere strtolower on args?).

Feature request: Block syntax for calling macros

For a macro defined like this:

{% macro fancy_box(content,title) %}
  <div class="box">
    <div class="top"><h3>{{ title }}</h3></div>
    <div class="content">{{ content }}</div>
    <div class="bottom"></div>
  </div>
{% endmacro %}

Instead of having to define all arguments first (or type them inline), it would be more natural to call it like this:

<div class="sidebar">
  {% layout.fancy_box('Recent Posts') %}
    <ul>
      {% for link in recentPosts %}
        <li><a href="{{ link.href }}">{{ link.title }}</a></li>
      {% else %}
        <li>No recent posts</li>
      {% endfor %}
    </ul>
  {% end layout.fancy_box %}
</div>

Something like this lets designers easily build up abstractions on unavoidably messy chunks of HTML, such as one may often end up with when (e.g.) building resilient layouts that support older browsers. Of course we can already achieve the same thing with macros if we're willing to define the content chunk with a {% set %} tag first, but that hides the structure of the document: A 'fancy_box' is essentially an elaborate wrapper of its main content, and its better if it can look like it. We could also achieve something more like my desired calling syntax by writing fancy_box as a filter, but then we have design matters wrapped up in our PHP extension to Twig.

As far as the actual behavior of this syntax, the block content should become the first argument, pushing other arguments down. (So the block content becomes 'content', the first argument becomes 'title'.) This won't always make sense for macros not designed to be used this way, but I don't think that matters very much. I don't know if the tags can be implemented like I've suggested. Maybe it has to be:

{% use layout.fancy_box('Recent Posts') %}
  ...
{% enduse %}

Or something like that.

occasional I18N extension ngettext problem

I'm not sure, but maybe there's bug with the plural form...
I've tried a simple example, as showed in the documentation:

{% trans count %}
    I have one apple.
{% plural %}
    I have {{ count }} apples.
{% endtrans %}

and this get's compiled to:

echo ngettext("I have one apple.");

obviously this generates a runtime error, because ngettext expects two
more parameters...

It seems that the problem is in the if condition at line 50 of the class Twig_Node_Trans:
if ($vars)
I think that changing this line to
if ($vars || $vars1 )
will fix the problem.

It seems that this kind of problem happens only when you use no vars on the singular form and some var on the plural form. That's why the proposed fix seems to work...

{% parent %} doesn't work with nested blocks

I have the following code:

{% block head %}
    This is the content of the HEAD block

    {% block assets %}
        This is the content of the ASSETS block
    {% endblock assets %}

    {% parent %} // LINE 13 

{% endblock head %}

And i receive the following error:

Twig_SyntaxError: Calling "parent" outside a block is forbidden in layout.html at line 13

where the line 13 is the marked one!

Is this a Twig bug or a wrong usage of blocks and parent nodes?

Lazy token parsers instances creation

Class Twig_Extension contain method getTokenParsers wich return array of instances.
Does it possible return just class names and create they instances on demand? We can make memory usage lower by this.

Twig_TokenParser::getTag need to be static.

Twig_Environment::loadTemplate should not accept just "names"

I have a loader that loads objects. If the object implements a Project_ResourceInterface, that provides a method getSource(), then the loader can handle this object and return the source.

It works very, very well. I can have the following sintax in my templates:

{{ include page.part.body }} -- or something similar

The only problem is this line at Twig_Environment class:

return $this->loadedTemplates[$name] = new $cls($this);

If $name is a object, I get a PHP Illegal offset type error. I've changed that to:

return $this->loadedTemplates[(string) $name] = new $cls($this);

and each of my resources have a __toString method that returns a unique identifier.

I think you could make that a bit more flexibe if those loadedTemplates was generated in a more flexibe way, maybe calling a method from the loader.

[enhancement] make foo.bar faster

Quote from docs:

For convenience sake foo.bar does the following things on
the PHP layer:

  • check if foo is an array and bar a valid element;

-----

  • if not, and if foo is an object, check that bar is a valid property;
  • if not, and if foo is an object, check that bar is a valid method
    (even if bar is the constructor - use __construct() instead);
  • if not, and if foo is an object, check that getBar is a valid method;

-----

  • if not, return a null value.

I propose add to options possibility to disable all steps between -----. Yes, I can use foo['bar'] in templates for this, but foo.bar more usable.

Dynamic access to object properties

obj['prop'] will return value only if obj is array and there is no way to get object property if we have it's name in a variable: obj[propName] will return null

LimeAutoloader not inclunded in Twig?

Hello,

I've donwloaded the latest snapshot (with i18n support) and I've startet to run tests mit it seems not work.
Where can I get the lime package?
I get this error in each test dir: Unable to access testing/php/templates/twig/develope/test/unit/../lib/lime/LimeAutoloader.php

Thanks
Michael

Incorrect results compiling large templates

(1) Create a large template
(2) The beginning of the template should be text only
(3) At the end of the template, have a for loop

Twig won't notice the for loop. It will think of it as text.

An example template:

asdfasdfadsfadsfads
(repeat that maybe 300 times or so)
{% for x in y %}
print "bob"

{% endfor %}

Expected: A lot of text followed by an empty for loop

Seen: A lot of text followed by the literal characters { - % - - f - o - r ......

If it matters, I'm also using the sandbox extension and PHP 5.2.5

Macros and filters.

I'm trying to trim some whitespaces in templates so I introduced a new
filter trim (mapped to PHP's trim). I noticed that

{% filter trim %}
...some output...
{% endfilter %}

works fine alone, inside {% block %} but not inside {% macro %}.

Also checked with some pre-defined filters as upper.

{{ someimport.somemacro(somevar)|upper }} also doesn't works.

Checking for __get magic function

I have objects with a few 'virtual' properties that are handled by the _ _get and _ _set magic functions. Twig doesn't check for this if i use something like {{ foo.bar }}.
According to the manual:

* check if foo is an array and bar a valid element;
* if not, and if foo is an object, check that bar is a valid property;
* if not, and if foo is an object, check that bar is a valid method;
* if not, and if foo is an object, check that getBar is a valid method;
* if not, return a null value. 

I would like to see "if not, and if foo is an object, check that _ _get is a valid method and bar is returned by it" to this list.

Type problems in templates

{% if key == formData[name] %} is true when key = 0 and formData[name] = 'all'

If I do the following this fixes it but it is nasty: {% if key~ == formData[name] %}

Autoescape makes filters unusable and context-bound

How do I write a 'truncate' filter so that it works with or without auto-escaping?

Let's say that myvar contains the string 'foo&bar'. Then, myvar|trunc(5) should yield 'foo&b'.

But if I have (html) auto-escaping on, the filter breaks! The filter function gets 'foo& bar' and thus returns 'foo&a' which is both logically incorrect AND invalid html.

Suggestion to fix: auto-escape only after the filters.

Macros are not affected by custom visitors

I've just created a node visitor and noticed, that it does not works inside macros. Problem is in Twig_Node_Module::getNodes(), there are should be something like this:
public function getNodes()
{
return array_merge(array($this->body), $this->blocks, $this->macros);
}

Incompatibility wih mbstring.func_overload turned on

  1. Put utf8 text and some Twig tags in a template
  2. Set in php.ini: mbstring.func_overload = 1 | 2
  3. Parser works incorrectly and fails for example with Twig_SyntaxError
    Should i post a case? I didn't research but think there is some mbstring/unicode-unaware string handling in the parser or compiler.

Nested arrays and function call

It is ok to make nested array like this:
{{ ['Dog': ['name': 'Meow', 'has': ['tail', 'legs']]] }}
but when i'm trying to pass this array to some function
{{ table.drawAnimal(['Dog': ['name': 'Meow', 'has': ['tail', 'legs']]]) }}
i'm getting Fatal error: Maximum function nesting level of '100' reached, aborting!
but this is ok:
{{ table.drawAnimal(['Dog': ['name': 'Meow']]) }}

Extended macro syntax

It will be great to have not only "inline" macro executing syntax like

{{ mymacros.macro(arg1, arg2) }}

but also have additional "block" syntax, to pass blocks of code as arguments

{% emacro mymacros.macro %}

    {% param arg1 %}
    <h1>Heading</h1>
    {% endparam %}

    {% param arg2 %}
    <p>Some markup</p>
    <ul>
     {% for item in list %}
     <li>{{ item }}</li>
     {% endfor %}
    </ul>
    {% endparam %}

{% endemacro %}

Also we can leave "inline" way to pass arguments, but "block" arguments have advantage

{% emacro mymacros.macro('<h1>Heading</h1>') %}

    {% param arg2 %}
    <p>Some markup</p>
    <ul>
     {% for item in list %}
     <li>{{ item }}</li>
     {% endfor %}
    </ul>
    {% endparam %}

{% endemacro %}

Constructor called instead of method

Hi, I found this possibly bug.
Suppose I have a class named "Result" with a constructor with same name and a method named "getResult":

class Result
{
    public function Result(foo, bar)
    {
        // object initialization
    }

    public function getResult()
    {
        // return some data
    }
}

Then I assign to template vars this array:

$result = new Result(foo, bar);
array("data" => $result);

When I try to access via templates as following
{{ data.result }}
it's resolve the constructor method as the method to call instead of getResult().

I think you should discern when a method is a class constructor and when not.

autoescaping type

By default uses html autoescaping type. How can I change autoescape to js? Something like this

<head>
{% autoescape on js %}
<script type="text/javaxcript">
    var lang = {
        placeholder : {{lang.placeholder}},
        txt2            : {{lang.txt2}}
    }
</script>
{% endautoescape %}

[feature] Add support for YAML frontmatter

The option of YAML frontmatter at the beginning of a template is a great way to bootstrap template developers into the world of rendering templates they are developing. It increases the speed of development because template developers can see the consequences of their changes right away.

I've come up with a proof-of-concept that works on the command line with help from the sfYaml library: http://gist.github.com/319596

[enhancement] for without loop

Hello, Fabien.

Some time ago we have discuss about possibility make for tag faster when magic variable .loop not needed. You have implemented this feature in 0.9.5, thanks.

But:

  1. this moment doesn't documented in 02-Twig-for-Template-Designers.markdown
  2. I don't need this magic variable .loop and don't want always print "without loop". Yes, I'm very lazy =). So: can you add settings for for tag: by default make .loop avalible in templates or not.

pass by value in block node

I think that in
Twig/lib/Twig/Node/Block.php lib/Twig/Node/Block.php on line 68

instead :
->write(sprintf("public function block_%s($context)\n", $this->name), "{\n")
must be:
->write(sprintf("public function block_%s(&$context)\n", $this->name), "{\n")

This need in case when need set value to context in child template and then parent read that value.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.