electronic.alchemy :: Simple Template
electronic.alchemy
where the past meets the future
pike > Fins > Simple Template

Simple Template

Created by hww3. Last updated by hww3, 197 days ago. Version #14.

Simple Template Syntax

Overview

The default template system provided with Fins is called Fins.Template.Simple. The format of this template system is similar to most others, in that you have HTML (or XML or text) that is sprinkled with specially formatted markup statements.

Simple templates are compiled at runtime into Pike code and cached for subsequent requests. This means that the time taken to interpret and compile a Simple template is only incurred if the template has not already been interpreted. Once compiled, the data prepared for the request by your controller is passed to the resulting pike code and the result is sent to the browser. This technique is used by a few other high performance template systems, such as JSP. The result is optimal performance with very few restrictions placed on the template designer (and most of those are done to enforce the MVC paradigm, rather than being limitations of the system itself).

In general, all Simple template markup consists of operations surrounded by <% and %>. We'll describe each of the various types of operation below. One limitation is that parsing is not recursive, so you can't nest operations within each other (that is, you can't have <% operationA <% operationB %> %>). This also means that the output of your page won't be reparsed for markup, so any special Simple template markup your template generates will be passed right on out (which is additionally a nice security feature). The upside is that your code will run faster and be much more maintainable. There are very few tasks that must be performed in a recursive manner, so this isn't a big deal. If you need to have a greater than or less than sign within your markup, simply double it in order to escape the syntax.

Some operations take arguments, such as the loops and macros. The arguments consist of a set of name-value pairs. The format of each argument will look like this:

name="value"

Note that this syntax is very particular. You must use quotation marks, the argument names are case sensitive, and you can't use spaces around the equal signs.

Declarations

The Simple template system has a few commands that don't fall into any other category. These are used for mostly template level operations, such as including another template within the current template.

<%@ include file="path/to/template.phtml" %>

Note that this is currently a path from the root of the template directory; even though it's not absolute, it's still calculated from the template root. Also note that included templates aren't automatically reloaded when they change (if using the reload templates feature). Currently, you'll have to restart your application to get templates reloaded.

Variable substitution

Probably the most important task of any templating system is to insert data into the resulting page in the right places. To insert a variable defined in the dataset provided by your controller, you use the following syntax:

<% $myValue %>

If you want to access values nested within a mapping in your dataset, you specify the "path" to that value, with the elements separated by a dot ("."). For example, if your dataset has a value called "myMapping", that is a mapping which contains a few values, we can use the following syntax to get at a hypothetical value "myValue" in that mapping:

<% $myMapping.myValue %>

Any values you try to substitute will be cast to a string, so if you embed objects, you can substitute them provided that they have a suitable cast output. The default behavior is to not throw errors if you try to access a value that doesn't exist, though in these situations, you will get a zero (0) in its place. This lets you know that your code is being parsed correctly.

Also, the insert code is flexible about spaces (but not newlines) after the opening tag (<%) and before the closing tag (<%). This means that any of the following substitutions will work just fine:

<% $myValue %>
<%$myValue%>
<%$ myValue %>

Control statements

Like any good templating system, Simple templates allow you to perform basic control operations. In particular, you have access to the basic "if-elseif-else" arrangement, and a set of powerful test statements.

The syntax for these control statments looks something like this:

<% if  sometest %>
<% elseif someothertest %>
<% else %>
<% endif %>

Where "sometest" and "someothertest" are expressions that will evaluate to either true or false. The format of the expression language is pure pike at this time, and is the only aspect of the Simple templating system subject to major revision. Expressions have access to the dataset as "data", and any valid Pike expression may be used.

For example, suppose we have a dataset that contains a mapping "user", which in turn has an index "userid" that is an integer. If we wanted to print "welcome old timer" for any user whose userid is less than 50, and "welcome newbie" for any other userids, we'd do the following:

<% if data["user"]["userid"] < 50 %>
  Welcome, old timer!
<% else %>
  Welcome, newbie!
<% endif %>

Note that when we access items from our dataset, we use the [ create ] indexing syntax rather than ->. This is because objects descended from Fins.Model.DataObjectInstance make their fields available using [ create ], in order to keep fields from masking DataObjectInstance methods. If you know that you won't be running across any of these methods, you can use the -> syntax instead, as it's slightly easier to type.

Loops

You can output the elements of any datatype or object that has a valid iterator. This includes all of the basic Pike datatypes, plus any objects you create that have iterators (such as model queries that return a list of Model objects.)

The foreach (iterator) operation takes 2 arguments: var and val. The argument "var" is the name of the item in your dataset that we want to iterate over, and the argument "val" is the name we can use to access the individual items as we iterate over them. You may optionally specify an index field using the argument "ind". Everything between the "foreach" tag and the "end" tag will be repeated once for each item in the list we're looping through. Any Simple template markup within that block will be evaluated for each element. Within the foreach operation, we can also execute output if there were no items in the iterator. This is the "forelse" operation, and is optional. Here's what the basic syntax looks like:

<%foreach var="X" val="Y"%>
  Item: <%$Y%>
<%forelse%>
  No items
<%end%>

But first, a few words about parameters...

Parameters

This section is likely to be the most confusing aspect of Simple templates. It helps to have a sample application with a test template you can explore with.

As we're seeing, many PSP operations require you to provide arguments in the form of arg="value". In order to allow functionality where you might either want to specify a literal value or a variable that will be looked up at render time, a special syntax is introduced. For arguments whose value specifies something that is to be read and used, you can either provide a string literal, or a variable reference, which has a syntax identical to the variable substitution syntax. By convention, these arguments tend to be named "var", though that's not a hard and fast rule.

Getting ahead of ourselves a bit, let's look at a simple macro example:

  <%capitalize var="october" %>

will yield

  October

whereas

  <%capitalize var="$october" %>

will cause the template to look for the field "october" in the template dataset. This syntax is used only in places that expect data as input, so you will have a mix of arguments with and without the dollar syntax.

Take the following (slightly more complex and more on-topic) example, a foreach loop. We want to loop through the values in the dataset item "manyitems", which has been provided to us by a controller. We want to place the index (key) and values for each item in "manyitems" into the dataset items "index" and "oneitem" respectively. Note that we use a dollar sign ($) before "manyitems" indicating we want to look up that value in the dataset. If we accidentally omitted the dollar sign ($), the loop would still run, but we would be iterating over the string literal "manyitems" rather than the desired item in our dataset.

You'll also notice that the other two arguments to our foreach loop aren't preceded by a dollar sign. That's because we only need to use dollar signs for template actions that require a value. The ind and val arguments are the names of fields into which we will place the data, so no dollar sign is necessary (ie, placing the key and values into a string literal would make no sense).

<% foreach var="$manyitems" [ind="index"] val="oneitem" %>
  Item <% $index %> is <% $oneitem %>.
  … our block to repeat ...
<% end %>

It's a good exercise to try this with both in order to get a feel for what will happen. In the example above, if we omit the dollar sign from "$manyitems", our foreach loop will iterate over each character in the string "manyitems", passing an integer containing the character position as the index, and an integer containing the character as the value.

For example, if we had a dataset with the element "books", which contained an array of Book objects, and a Book object had a field called "title", we could write the following code to print a list of all of the Books titles:

Here are all of the books we have:

<% foreach var="$books" val="onebook" %> We have a book called: <% $onebook.title %> <% end %>

Macros

Fins provides the ability to write code that you can call within your templates. While we strive to maintain the MVC relationship, there are obviously situations where it becomes necessary to run code in order to produce an acceptable user interface. We arrived at a compromise by which you cannot directly embed pike code within a template, but instead offer the ability to write and run macros from within your pages. A macro is a specially written pike function that will receive a copy of the the event dataset, and a set of arguments provided by the macro invocation within the template itself. This allows you to perform all kinds of display domain processing while still retaining MVC separation of duties.

Fins comes with a number of macros, and you can write your own (a topic for a different time). The way to call a macro from a template looks like this:

<% macro_name args %>

Where macro_name is the name of the macro you wish to call, and args is a list of arguments, much as we use in the foreach loop above. The actual arguments expected (if any) by a macro will vary. Check with the documentation for the macro you'd like to use for details.

For an example, we'll use the "capitalize" macro, which will capitalize an item from your dataset and output it. It takes an argument, "var", which is a dot-separated path to the element in your dataset, much like in the variable substitution section above:

<% capitalize var="$myMapping.myValue" %>

This invocation will get the value of the key "myValue" held in the mapping "myMapping" of our dataset, capitalize it and return it. You can browse the other macros available by default with Fins by looking at the documentation for the Fins.Helpers.Macros module.

Layouts

A layout is a template that contains the layout "shell" for an event. The Fins.Template.Simple.set_layout() method can be used to set the layout manually, or you can use the DocController controller class to automatically select templates and layouts based on the request. When using DocController, the following paths will be searched for a layout file: templates/layouts/path/to/controller.phtml, all paths to the parent controller's layout file, and templates/layouts/application.phtml. The first template file located from these paths will be used as the layout for that controller.

Layouts work and are written identically as standard templates with one exception: at the point in the layout file that you wish the event's template output to be inserted, you use the <%yield%> construct. When the rendering process reaches that point in the layout file, the event level template will be rendered and inserted in the output stream.

The following file template file:

<html><title>test</title></head>
<body>
<%yield%>
</body></html>

When used as a layout in combination with the following template file:

foo!

Will produce the following output:

<html><title>test</title></head>
<body>
foo
</body></html>

As mentioned, layouts can be used and managed on a case-by-case basis in your controller, but using DocController makes life much simpler, especially when writing applications that have a large number of event->template pairs.

Future directions

As of the writing of this document (February 2008), most aspects of the Simple template system are stable. We only anticipate making changes that add functionality or remove limitations in the implementation as described here.

The only aspect of this system that is subject to change is the syntax of test statements used by "if-elseif-else". In the event that a more robust system is developed, the old syntax will be made available by means of a flag within the configuration file or similar mechanism.

Not categorized | RSS Feed | BackLinks

comments powered by Disqus