What’s a “conditerator”?

September 8th, 2009 by Doug Martin

One of the core features of Tierra Templates is a new code construction called a “conditerator.”    Conditerators combine an if condition with a loop iterator and greatly reduce the size and complexity of your templates.

One of the most common code patterns you see in pure PHP code or other templating engines is this:

if (isset($users) && (count($users) > 0) {
  echo "<div id='users'>Users:<ol>";
  foreach ($users as $user)
    echo "<li>{$user->fullname}</li>";
  echo "</ol></div>";
}
else
  echo "No users found";

Conditerators reduce that code to this:

{@ users ? "<div id='users'>Users<ol>" `<li>{fullname}</li>` "</ol></div>"
else "No users found" @}

Conditerators can be read like PHP’s ternary if with the colon (:) replaced with the keyword “else” (the colon character is used in the templating syntax to link up filter functions so it can’t be used here without introducing ambiguity to the parser).  In the template conditerators  are delimited with {@ and @} and have the following syntax:

{@ (<statement>;)* [expression] ([if <expression] ? [<before loop output>]
 [<loop output>] [<after loop output>])+  [else <else output>] @}

The optional leading list of statements allow you do to assignments and related function calls before the main expression (if present) is evaluated using the following code:

if (is_array($expression) || is_object($expression))
  $result = count($expression) > 0;
else if (is_string($expression))
  $result = strlen($expression) > 0;
else if (is_int($expression))
  $result = $expression != 0;
else
  $result = $expression;

this differs slightly from PHP’s empty() function in that strings with “0″ are true.

If the expression is true then right side of the ? is evaluated with up to 3 output expressions being accepted.  If the expression is an array then the loop output is evaluated with each item in the array, otherwise  it is only output once.  If the expression is false, then the single else output expression is used.

Here are some more examples of simple conditerators and their output after the =>.

{@ “foo” @} => “foo”

{@ bar = false; “foo” if bar else “bam” @} => “bam”

{@ bar = 1; “foo” if ((bar * 3) < 2) ? bar else if ((bar * 3 < 10) “bam” else “boom” @} => “bam”

{@ bar = 1; if bar < 2 ? “foo” else “bam” @} => “foo”

Here are some conditerators showing Tierra Template’s built in support for JSON.  The ‘$’ character is a special variable meaning the current value of the conditerator loop.  There are other special values like $previous, $next, $first, $next, $count, $even, $odd, etc.

{@ [1,2,3,4] ? $ @} => “1234″

{@ [1,2,3,4] ? “Numbers: ” $ @} => “Numbers: 1234″

{@ [1,2,3,4] ? “” $ ” – after” @} => “1234 – after”

{@ [1,2,3,4] ? “foo” @} => “foofoofoofoo” @}

{@ [1,2,3,4] ? `<p>{$}</p>` @} => “<p>1</p><p>2</p><p>3</p><p>4</p>”

{@ [[1,2,3],4,[5,6]] ? (count($) > 1 ? “foo” else $) @} => “foo4foo” @}

Finally here is a conditerator containing another conditerator.  The $$ special variable is the value of the parent loop, $$$ is the grandparent, etc.  The template syntax uses dot notation to access members of an object so $$.name in the conditerator below means the name attribute of the current loop value of the parent loop.

{@ [{id: 1, name: "Fred", posts: [{id:1000, title: "Test"}]}, {id: 2, name: “Barney”}] ? (posts ? `<p>{$$.name}<ol>` `<li><a href=”/post/{id}”>{title}</a></li>` “</ol></p>”) @} => “<p>Fred<ol><li><a href=”/post/1000″>Test</a></li></ol></p>”

I hope this has been a clear introduction to the power of conditerators.  As we flesh out the documentation in preparation of the initial beta release we’ll include a cookbook of common conditerators.  Please let us know what you think and if there are any other examples you would like to see.

Bookmark and Share

Leave a Reply