{% endfor %}
</ul>
-Inside of a for loop block you can access some special variables:
+>**NOTE**
+>A sequence can be either an array or an object implementing the `Iterator`
+>interface.
+
+Inside of a `for` loop block you can access some special variables:
| Variable | Description
| --------------------- | -------------------------------------------------------------
| `loop.last` | True if last iteration
| `loop.length` | The number of items in the sequence
-Unlike in PHP it's not possible to `break` or `continue` in a loop.
+>**NOTE**
+>Unlike in PHP it's not possible to `break` or `continue` in a loop.
If no iteration took place because the sequence was empty, you can render a
replacement block by using `else`:
{% for user in users %}
<li>{{ user.username|e }}</li>
{% else %}
- <li><em>no users found</em></li>
+ <li><em>no user found</em></li>
{% endif %}
</ul>
+By default, a loop iterates over the values of the sequence. You can iterate
+on keys by using the `keys` filter:
+
+ [twig]
+ <h1>Members</h1>
+ <ul>
+ {% for key in users|keys %}
+ <li>{{ key }}</li>
+ {% endfor %}
+ </ul>
+
+You can also access both keys and values:
+
+ [twig]
+ <h1>Members</h1>
+ <ul>
+ {% for key, value in users %}
+ <li>{{ key }}: {{ user.username|e }}</li>
+ {% endfor %}
+ </ul>
+
+>**NOTE**
+>On Twig before 0.9.3, you need to use the `items` filter to access both the
+>keys and values (`{% for key, value in users|items %}`).
+
### If
The `if` statement in Twig is comparable with the if statements of PHP. In the
...
{% endfor %}
-### `items`
-
-The `items` filter is mainly useful when using the `for` tag to iterate over
-both the keys and the values of an array:
-
- [twig]
- {% for key, value in array|items %}
- ...
- {% endfor %}
-
### `escape`, `e`
The `escape` filter converts the characters `&`, `<`, `>`, `'`, and `"` in
public function initRuntime()
{
require_once dirname(__FILE__).'/../runtime.php';
- require_once dirname(__FILE__).'/../runtime_for.php';
}
/**
$compiler->write("\$context['_iterated'] = false;\n");
}
+ if ($this->isMultitarget)
+ {
+ $loopVars = array($this->item[0]->getName(), $this->item[1]->getName());
+ }
+ else
+ {
+ $loopVars = array('_key', $this->item->getName());
+ }
+
$var = rand(1, 999999);
$compiler
->write("\$seq$var = twig_iterator_to_array(")
->subcompile($this->seq)
->raw(");\n")
->write("\$context['loop']['length'] = count(\$seq$var);\n")
- ->write("for (\$i$var = 0; \$i$var < \$context['loop']['length']; \$i$var++)\n")
+
+ ->write("\$context['loop'] = array(\n")
+ ->write(" 'parent' => \$context['_parent'],\n")
+ ->write(" 'length' => \$context['loop']['length'],\n")
+ ->write(" 'index0' => 0,\n")
+ ->write(" 'index' => 1,\n")
+ ->write(" 'revindex0' => \$context['loop']['length'] - 1,\n")
+ ->write(" 'revindex' => \$context['loop']['length'],\n")
+ ->write(" 'first' => true,\n")
+ ->write(" 'last' => false,\n")
+ ->write(");\n")
+
+ ->write("foreach (\$seq$var as \$context[")
+ ->repr($loopVars[0])
+ ->raw("] => \$context[")
+ ->repr($loopVars[1])
+ ->raw("])\n")
->write("{\n")
->indent()
;
$compiler->write("\$context['_iterated'] = true;\n");
}
- $compiler->write("twig_set_loop_context(\$context, \$seq$var, \$i$var, ");
-
- if ($this->isMultitarget)
- {
- $compiler->raw('array(');
- foreach ($this->item as $idx => $node)
- {
- if ($idx)
- {
- $compiler->raw(', ');
- }
- $compiler->repr($node->getName());
- }
- $compiler->raw(')');
- }
- else
- {
- $compiler->repr($this->item->getName());
- }
-
$compiler
- ->raw(");\n")
->subcompile($this->body)
+
+ ->write("++\$context['loop']['index0'];\n")
+ ->write("++\$context['loop']['index'];\n")
+ ->write("--\$context['loop']['revindex0'];\n")
+ ->write("--\$context['loop']['revindex'];\n")
+ ->write("\$context['loop']['first'] = false;\n")
+ ->write("\$context['loop']['last'] = 0 === \$context['loop']['revindex0'];\n")
+
->outdent()
->write("}\n")
;
return ucfirst(strtolower($string));
}
}
+
+function twig_iterator_to_array($seq)
+{
+ if (is_array($seq))
+ {
+ return $seq;
+ }
+ elseif (is_object($seq) && $seq instanceof Iterator)
+ {
+ return iterator_to_array($seq);
+ }
+ else
+ {
+ return array();
+ }
+}
+
+// only for backward compatibility
+function twig_get_array_items_filter($array)
+{
+ // noop
+ return $array;
+}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) 2009 Fabien Potencier
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-function twig_iterator_to_array($seq)
-{
- if (is_array($seq))
- {
- return array_values($seq);
- }
- elseif (is_object($seq) && $seq instanceof Iterator)
- {
- return iterator_to_array($seq, false);
- }
- else
- {
- return array();
- }
-}
-
-function twig_set_loop_context(&$context, $seq, $idx, $target)
-{
- if (is_array($target))
- {
- $context[$target[0]] = $seq[$idx][0];
- $context[$target[1]] = $seq[$idx][1];
- }
- else
- {
- $context[$target] = $seq[$idx];
- }
-
- $context['loop'] = array(
- 'parent' => $context['_parent'],
- 'length' => $context['loop']['length'],
- 'index0' => $idx,
- 'index' => $idx + 1,
- 'revindex0' => $context['loop']['length'] - $idx - 1,
- 'revindex' => $context['loop']['length'] - $idx,
- 'first' => $idx == 0,
- 'last' => $idx + 1 == $context['loop']['length'],
- );
-}
-
-function twig_get_array_items_filter($array)
-{
- if (!is_array($array) && (!is_object($array) || !$array instanceof Iterator))
- {
- return false;
- }
-
- $result = array();
- foreach ($array as $key => $value)
- {
- $result[] = array($key, $value);
- }
-
- return $result;
-}