The StoreFront Template Language
The StoreFront uses the Velocity templating language written by the Apache Software Foundation. UltraCart selected this templating language because it has an active community pushing the language forward, it is incredibly fast, and its syntax meshes nicely with HTML. Velocity is not meant to be a full-blown programming language. Velocity is meant to be a presentation language with a simple syntax that makes building interactive web pages simple.
What about Wordpress? Why not PHP?
The UltraCart engine runs on a Java platform, not a PHP platform. While PHP and Wordpress have enjoyed tremendous success, our technology platform was built for specific reasons, and Velocity is a natural fit to those technologies.
This chapter will cover the basics of the Velocity language. The User Guide that covers all aspects of the language may be read at: http://velocity.apache.org/engine/devel/user-guide.html .
Before we dive into a discussion on the syntax of Velocity, let's first talk about what an "object" is from a programming point of view. An object is a single instance of a data structure within a running program. Each object has a well-defined set of operations that can be performed on the object. Let's use a real world example of an "Item" object. An "Item" object has numerous piece of data stored within it (description, cost , weight , dimensions, etc...). The object will expose operations, known as methods, that allow the programmer to extract and manipulate the data within an object. Almost all the data that you manipulate in your Velocity template is an object of one type or another. In this chapter, we are not going to cover all the various types of objects in the catalog system, but the actual Velocity syntax that is used to manipulate objects.
References
The first concept in Velocity is a reference. A reference is how you access a given object to manipulate things. When your template executes, there will be many predefined objects that you can reference, but we want to look at how to set a basic reference and then access it later in the template. Let's look at a Hello World example.
<html> <body> #set( $foo = "Velocity" ) Hello $foo World! </body> <html>
There are actually two lines of Velocity code mixed within this HTML code.
The first line of Velocity code is assigning the string "Velocity" to a new object called "foo" using the set directive.
The second line of code is outputting the value of "$foo" into the rendered template. If you were to place this code into a template and then load the page it would say "Hello Velocity World!" as the output.
Comments
Any good programming or scripting language will allow you to have comments in the code that will not appear in the final product (in the case of Velocity, the rendered HTML page). In Velocity, a comment is all the text on the line that comes after two hash symbols (#) in a row. Let's take our Hello World example from the references section and add some comments.
<html> <body>## Assign the value of Velocity to the variable $foo #set( $foo = "Velocity" )## Inject the contents of $foo into our Hello World statement Hello $foo World! </body> <html>
While this may be total overkill for a Hello World example, comments are a great idea to include in your code. You may know everything that you're doing in a complex piece of code, but are you going to remember your decisions six months from now? What if another web developer has to come behind you and maintain or enhance the code? The bottom line is that comments are worth your time to write and will pay dividends in the future.
You can also include multi-line comments within your code by starting a line with a pound symbol immediately followed by the asterisk symbol "#*" and ending another line with the symbols reversed "*#". Below is an example of a multi-line comment from the Velocity User Guide.
This is text that is outside the multi-line comment. Online visitors can see it. #* Thus begins a multi-line comment. Online visitors won't see this text because the Velocity Template Engine will ignore it. *# Here is text outside the multi-line comment; it is visible.
Variables
Variables are accessed using a shorthand notation of a leading dollar sign ($) followed by the variable name. Variable names can contain alphabetic characters, numeric characters, hyphens and underscores. Since the hyphen is commonly used in math equations, we don't recommend using it in your variable names. Instead, we recommend using a Java style camel case naming convention. For instance, a variable to store the time might be named $currentTimeString.
Variables receive their values in two ways: (1)a #set
statement, or (2) it is already defined in the context provided to the template. We will cover the context variables available to you in a later chapter.
Methods
Each variable in your Velocity template is actually an object that has many methods available. Some methods will return a value and other methods will require parameters. The complete documentation for those objects may be found in the StoreFront Object Model.
For this example, we will show how to call a set method to store a value in custom field 1 on the cart and then fetch it.
$cart.setCustomField1("My Value")
$cart.getCustomField1()
There is also a format reference notation in Velocity where you individual statements have curly brackets at the beginning and end. Here are the same two statements with formal notation:
${cart.setCustomField1("My Value")}${cart.getCustomField1()
}
Most of the time formal notation is not required, but there are times when you need to embed Velocity code into HTML. The brackets keep the rendering engine from confusing the Velocity statement from HTML code. The item page link from the Hello World example in Chapter 2 illustrates the need for formal notation:
<a href="${baseUrl}${group.getPath()}${item.getMerchantItemID()}.html">${item.getDescription()}</a>
Note that there are numerous Velocity statements in a row to build up the URL to the item page. If formal notation was not used on the getMerchantItemID call, then it would expect the result of that method call to be an object that had a method "html" on it. This would cause the Velocity statement to fail.
Quiet Reference Notation
If a Velocity statement is not valid or there is nothing assigned to a variable, then the default behavior of the language sends the statement to the rendered output. This is useful for debugging, but it is not the desired behavior in a production template. Velocity makes it easy to prevent this behavior with quiet reference notation. By placing an exclamation mark after the dollar sign Velocity will suppress the output from the method call. Here is an example of the syntax:
<input type="text" name="email" value="$!email"/>
If the variable "$email" doesn't have a value assigned to it, then writing it as "$!email" with an exclamation mark will cause an empty string to be rendered instead of outputting "$email" to the rendered template.
Setting a Variable
Velocity uses the #set
syntax to assign a value to a variable. The value can be for a constant string value or the result of another function. Here is an example of assigning a constant number to a variable:
#set($foo = "hello world")
Here is an example of assigning the value of a function call to a variable:
#set($foo = $cart.getCustomField1())
It does not matter if the variable "foo" has already been defined. If it has been defined, then the variable will be updated. Otherwise, the variable will be initialized and assigned the value.
Conditional Directives
Velocity supports common directions, such as if, if/else, and if/else/if/else style conditional directives. The simplest conditional directive is a basic "#if" statement.
#if( $foo ) <strong>Foo is true!</strong> #end
As long as the variable "foo" evaluates to true, then the HTML code between the #if and the #end statement will be included in the rendered output. You can also test a single condition and then output two different values.
#if( $foo ) <strong>Foo is true!</strong>#else Foo is false!#end Another common scenario is to evaluate multiple conditions to determine a value to display. This is accomplished with the "#if/#elseif/#else" syntax. #if( $foo == 1 ) <strong>North</strong> #elseif( $foo == 2 ) <strong> East</strong> #elseif( $foo == 3 ) <strong>South</strong> #else <strong>West</strong> #end
The first condition that evaluates to true will display the HTML between the two directives. If none of the statements evaluate to true, then the final "#else" content of "West" will be rendered.
Complex Conditional Statements
Velocity is like most languages in that it supports an AND (&&) , OR (||), and NOT operator for use in conditional statements.
Below is an example of each operator in use.
Logical AND
#if( $foo && $bar )
<strong> This AND that</strong>
#end
Logical OR
#if( $foo || $bar )
<strong>This OR That</strong>
#end
Logical NOT
#if( !$foo )
<strong>NOT that</strong>
#end
Like most languages, you can create complex conditional statements by surrounding operators with parentheses. For instance, if you want to render if "foo" is true or "bar" and "baz" are both true, then our statement would read:
#if ($foo || ($bar && $baz))Hello!#end
Loops
When you have a variable that represents a collection of objects (or an array), you can use a "#foreach" loop. This is the only type of loop construct that Velocity supports.
Let's review the "#foreach" loop that we used in the Hello World example in Chapter 2.
#foreach ($item in $group.getItems()) <a href="${baseUrl}${group.getPath()}${item.getMerchantItemID()}.html"> ${item.getDescription()}</a><br> #end
The object "$group" had a method "getItems()" that returned an array of all the items assigned to the group. The" #foreach" directive will loop through the array of items and assign each one to the variable "$item" as the loop goes around. Inside the loop, we used the "$item" object to fetch its description, as well as its item ID to generate the content we wanted on our page.
During a Velocity loop, the variable "$velocityCount" is automatically assigned the current index of the loop. This built-in variable is useful for looping through items and outputting a numbered list. Another common use of the "$velocityCount" variable is to stop the loop after a certain number of objects are processed. Let's take the loop above and stop it after ten loops.
#foreach ($item in $group.getItems()) <a href="${baseUrl}${group.getPath()}${item.getMerchantItemID()}.html"> ${item.getDescription()}</a><br> #if ($velocityCount >= 10) #break #end
Notice the use of a conditional "#if" statement within the loop to test the $velocityCount variable. If it is 10 or greater, the loop will stop by using the "#break" directive.
String Concatenation
The Velocity language is different than most languages with string concatenation. While most languages use a plus operator to concatenate strings, Velocity takes a different approach with the set statement. The following example will output "The structure is a bridge named Golden Gate".
#set($structure = "bridge")#set($name = " Golden Gate")#set($sentence = "The structure is a $structure named $name")$sentence
Math
Velocity has the typical mathematical operations found in most languages built-in: addition (+), subtraction (-), multiplication (*), division (/), and modulus (%). Below is an example of performing a mathematical operation on "bar" and assigning the result to the variable "foo".
#set( $foo = $bar + 3 ) #set( $foo = $bar - 4 ) #set( $foo = $bar * 6 ) #set( $foo = $bar / 2 ) #set( $foo = $bar % 5 )
You can create complex formulas that evaluate in a specific order with typical mathematical syntax by surrounding sub-operations with parentheses.