In addition to the substitution mechanisms shown in TemplateDoc, function substitutions provide a means of defining reusable substitutions, i.e. they are not bound to an instance of the Template class and thus can be used in all template files. The main idea is to define substitutions in a central place which then can be used in the whole project. The substitutions to be defined are the same as described in TemplateDoc.
Another key element of function substitutions is that they can operate on data objects, namely the assets in the scope of a template or its roles and properties (when a template is processed, there is at most one asset object in its scope). There are four different kinds of function substitutions: The simplest functions are static functions which do not rely on a data object in the scope (example: print the login of the current session user). Asset functions can produce output based on an Asset (example: print the URL of the asset in the scope). Property functions produce output based on a specific property of the asset in the scope (example: print the value of the property name of the asset in the current scope). Role functions do the same for roles. Additionally, all function substitutions can take an arbitrary number of parameters.
The syntax of function substitution placeholders is largely the same as the syntax of "normal" substitutions as described in TemplateDoc, with the difference that there are parentheses (and optionally parameters) at the end of the placeholder. The syntax of the placeholder of a print function substitution is as follows:
PrintFunction
$ [ Identifier { . Identifier } . ] FunctionName ( [ Parameter { ; Parameter } ] ) $
Parameter
ParameterName = ParameterValue
The optional identifiers are explained later.
Each project can define function substitutions in a Java class Functions.java. This class has to be in the package de.infoasset.%PROJECT_NAME%.handler. A function substitution is specified by creating a public static method, which returns one of the four basic substitution types: PrintSubstitution, ConditionalSubstitution, ListSubstitution, or TemplateSubstitution. The name of the method is the name of the function substitution. The following method defines a static function substitution which prints out the current date:
public class Functions {
...
public static PrintSubstitution currentDate(final FunctionParameters params) {
return new PrintSubstitution() {
@Override
protected String print() {
return new Date(System.currentTimeMillis()).toString();
}
};
}
...
}
The parameter of type FunctionParameters gives access to the parameters specified by the placeholder. Based on this example function substitution, the date can be accessed in each template by the placeholder $currentDate()$.
As already mentioned, there are four different types of function substitutions, static, asset, property and role function substitutions. They are specified using different method signatures. The currentDate function substitution is a static substitution, since it only gets parameter in its signature from the current context. An asset function substitution takes an asset as an additional parameter (this is not visible in the template file but only in the respective Functions.java file):
public static PrintSubstitution id(final CoreAsset a, final FunctionParameters params) {
return new PrintSubstitution() {
@Override
protected String print() {
return a.id.get();
}
};
}
The placeholder for this substitution is $id()$. This only works, if there is an Asset in the context of the placeholder. Each Templatable (like a complete HTML-page) can put an asset into its template scope. This is done with the Templatable.getAsset() method.
It is possible to define specialized function substitutions, which work on assets of a specific type:
public static PrintSubstitution documentTitle(final Document d, final FunctionParameters params) {
return new PrintSubstitution() {
@Override
protected String print() {
return d.title.get();
}
};
}
When processing a template, the most specific function substitution is applied.
Property and role function substitutions are defined the same way as asset function substitutions. Their defining method takes a subtype of Property or Role as a first argument:
public static PrintSubstitution propertyName(final Property p, final FunctionParameters params) {
return new PrintSubstitution() {
@Override
protected String print() {
return p.getName();
}
};
}
A placeholder for this function substitution would be $title.propertyName()$. This requires an asset in the scope, which has a property title.
Also for property and role function substitutions it is possible to define specialized functions, which only work on specific subtypes of Property and Role.
The table below shows how the identifiers mentioned in the beginning are interpreted when a placeholder in a template is processed. The letters in square brackets indicate which kind of functions it is looked for, when the respective case is encountered.
p means PropertyFunction
r means RoleFunction
s means StaticFunction
a means AssetFunction
As can be seen from the table, in case the respectively last identifier matches the name of a OneRole, it is first looked for a RoleFunction substitution for the respective role and function name. If no such substitution exists, it is looked for an AssetFunction substitution matching the function name and the class of the asset which the role is pointing to. If such a substitution exists it receives the actual asset the role is pointing to as a parameter.
Additionally, the behaviour is special if a function substitution placeholder is used within a list substitution: It is then first tried, to find a function substitution matching the asset class of the current asset in the list substitution before mathing the placeholder against a property or role of the asset in the scope of the template.
| number of identifiers | identifier 0 | identifier 1 | identifier 2 |
| 0 [a|s] | |||
| 1 | list-qualifier [a] | ||
| propertyName [p] | |||
| oneRoleName [r|a] | |||
| manyRoleName [r] | |||
| 2 | list-qualifier | propertyName [p] | |
| oneRoleName [r|a] | |||
| manyRoleName [r] | |||
| oneRoleName | propertyName [p] | ||
| 3 | list-qualifier | oneRoleName | propertyName [p] |
| oneRoleName [r|a] | |||
| manyRoleName[r] |