6. Migration
6.1. OPT 1.x
6. Migration
« Previous
6.2. PHP
Next »

6.1. OPT 1.x

Open Power Template 2 is a successor of Open Power Template 1 library, however it was written entirely from scratch and the backward compatibility actually does not exist. In this article, the users of the previous version may find useful information and tricks that will help them migrating to the new releases.

Programming interface

The library API has been simplified and many names have been changed to reflect their actual functions better. The code supports many new PHP5 features, such as autoloaders, SPL data structures and PHAR archives. The internal class data have been hermetized and it is not possible to modify them directly from the user space.

The basic issues:

  1. OPT relies now on the common Open Power Libs core that provides the basic functionality such as configuration management, debugging, plug-ins and error handling.
  2. The new class naming convention has been introduced: Opx_Class_Name.
  3. The Opt_Class class is not an all-in-one harvester anymore. Most of its functions have been moved to separate classes.
  4. The templates are represented in the script by views. They are simply objects of the Opt_View class and consist of the template and the data assigned to it.
  5. The template parsing and managing the output has been moved to output objects. They are objects of classes that implement the Opt_Output_Interface. The programmer may write new outputs easily by implementing the specified interface in his classes.
  6. There is no built-in caching mechanism in OPT 2, as this is not a template engine task. Instead, the cache port has been introduced where the programmer may plug-in any caching library using a simple interface.
  7. The plugin architecture and new item registration have been changed.
  8. The errors are still reported by exceptions, but now each error message has its own exception class. Moreover, they are grouped using the class inheritance which allows to capture only particular types of errors.

Template syntax

OPT 1 could not process XML documents, whereas OPT 2 does and makes a real use of this fact. The following compiler modes are available in the new version:

  1. XML mode - in this mode, the templates must be valid XML documents. OPT recognizes and processes XML/HTML tags.
  2. HTML mode - by disabling some XML standard features, you may activate less restrictive HTML mode. Here, OPT still recognizes and processes XML and HTML tags. See Configuration directives.
  3. Quirks mode - it is similar to XML compatibility mode from OPT 1.x. The compiler recognizes only OPT tags and the rest of the document is treated as a static text.

The mode does not affect the OPT tags which must be always valid XML tags. The curly brackets are used to put the OPT expressions in the static text.

<p>
<opt:if test="$variable">
    {$variable}
</opt:if>
</p>

The XML/HTML mode produces several extra implications. It is not allowed to write <tag {$variable}> or <tag attribute="{$variable}">. In order to add a dynamic attribute or tag, you have to use opt:attribute and opt:tag instructions, and to put a dynamic attribute value, you have to switch its namespace into parse::

<p parse:class="$cssClass"> ... </p>

The compiler does not allow to enclose the tags in the incorrect order (even in HTML) and this is the reason why the output must not be a concatenation of several templates executed one after another. In order to create modular templates, you have to use opt:include or template inheritance.

Expressions

The expression language is very similar, but there are some differences in the object access syntax. The naming rules are changed, for example blocks from OPT 1.x are simply called variables now.

The important change is the support for the HTML escaping of the expression results which allows to make automatic XSS filtering on the template side. In OPT 1, the following code would accept every possible value as the variables, even containing new HTML attributes or breaking the code:

<p {$value}>{$text}</p>

The result could be terrible:

<p style="aaa" javascript="aggressive code"><span>a variable that adds some HTML tags</span></p>

OPT introduces a smart three-level escaping control (script, per-template and per-expression control). The escaping rules are:

  1. Every expression put as an XML attribute value should be escaped.
  2. Every expression put as instruction attribute value will be escaped, if the instruction needs it.
  3. Every expression put in the static text will be escaped, if the current escaping policy requires it.

An example of turning on the escaping for a particular variable using the e: modifier:

<p>This variable will be escaped: {e:$variable}</p>

By default, htmlspecialchars() function is used to do the escaping, but the programmer may register his own escaping handler.

Remember that the escaping is not a magic solution for all your problems. While developing your script, you have to remember that the used features will never give you a full protection against all the possible attacks. First of all, they must be used properly and your code should not leave various potentially dangerous options enabled.

Sections

At a first sight, the sections did not change, and the basic functionality remains the same. However, the section behavior has been strictly defined in the new version, and the instructions themselves became more modular. This allows the programmers to create their own section instructions. By default, OPT provides four types of sections:

  1. opt:section - an ordinary section.
  2. opt:tree - displaying the tree. Similar to {tree} instruction from OPT 1.1, but the syntax is completely different.
  3. opt:selector - a combination of section and switch statement.
  4. opt:grid - displaying the items in columns.

They share the same API and may cooperate one with another. The programmer has much more control over creating relationships between the sections thanks to the parent attribute. For example:

<opt:section name="section1">
    <opt:section name="section2">
        <opt:section name="section3" parent="section1">
            ...
        </opt:section>
    </opt:section>
</opt:section>

The internal architecture of sections is now completely hidden to the template designer and configured on the script side. The same applies to the dynamic sections from OPT 1.1 that can be achieved now simply by choosing the StaticGenerator or RuntimeGenerator data format.

Other instructions

OPT 2.0 brings several new instructions and changes the semantics and/or names of the old ones.

  1. {bind} - renamed to opt:snippet and improved to make template inheritance possible.
  2. {insert} - renamed to opt:insert and improved to make template inheritance possible.
  3. {bindEvent} - not implemented. The same effects can be achieved with opt:snippet now.
  4. {bindGroup} - not implemented. The same effects can be achieved with opt:snippet now.
  5. {pagesystem} - not implemented. The same effects can be achieved with more general opt:selector.
  6. {var} - not implemented. Use the assignment operator.
  7. {default} - not implemented. The same effects can be achieved in other ways.
  8. {place} - not implemented. It did not really work correctly and you can achieve much better effects with template inheritance and opt:root.
  9. {php} - not implemented.

Components

The components are still present, but they have been redesigned from scratch to make use of the new features of OPT 2.0. It is much easier to design the component neighborhood and the components are more functional. The programmer may still decide, whether to work with them only on the template side or not. Below, you can find a code of a sample OPT 2.0 component:

<opt:myInput datasource="$fieldData">
    <com:div>
        <p>{$sys.component.title} <span opt:if="$sys.component.description">{$sys.component.description}</span></p>
        <opt:display />
 
        <opt:onEvent name="error">
            <p class="error">{$sys.component.errorMessage}</p>
        </opt:onEvent>
    </com:div>
</opt:myInput>

As you see, the component tag now defines the whole neighborhood and the place to display the component itself is marked with opt:display tag. Moreover, the component can control the HTML attributes of the surrounding tags, if they are moved to the com namespace.

Moreover, a much simpler alternative to components has been introduced: blocks.

Functions

The function set has been widely extended in OPT 2.0. Some of the functions have been ported to the last release of OPT 1.1 before closing that branch: 1.1.5. The significant improvement over OPT 1.x is that many functions became aggregates - they can modify either a single value or a list of values:

{@capitalizedNames is capitalize($names)}
<opt:section name="list" datasource="@capitalizedNames">
    <p>{$list}</p>
</opt:section>

Template modularization

Open Power Template 1.1 offered a limited number of modularization features. There was the include instruction and concatenating the output of the templates. Furthermore, due to the lack of views, the code was longer and harder to maintain.

The situation has changed dramatically in OPT 2.0. Concatenation is not possible anymore in the XML mode, but on the other hand, you get a more advanced opt:include and the dynamic template inheritance. opt:include has been extended to support views and integrated with sections. For example, different actions may create their own views, insert them into a list and the section would render them easily:

$tpl = new Opt_Class;
// some configuration here.
 
$contentContainer = array();
 
// Let's create some views...
$view = new Opt_View('template1.tpl');
$view->customVar = 'some value';
 
$contentContainer[] = array('view' => $view);
 
$view = new Opt_View('template2.tpl');
$view->anotherVar = 'some value';
 
$contentContainer[] = array('view' => $view);
 
// Let's create the main view:
 
$mainView = new Opt_View('main.tpl');
$mainView->content = $contentContainer;
$mainView->title = 'Some title';
 
// Rendering the views:
$output = new Opt_Output_Http;
$output->render($mainView);

And the template code:

<html>
<head>
    <title>{$title}</title>
</head>
<body>
<opt:section name="content">
    <opt:include from="content"><p>Sorry, the specified template has not been found.</p></opt:include>
</opt:section>
</body>
</html>

One of the view advantages is the fact that each view has its own variable scope and you do not have to worry about the naming collisions between different modules. See template inclusion to get to know more.

Another concept, completely new in the OPT project, is the template inheritance, quite similar to the inheritance in the object-oriented programming. Instead of classes, we extend templates and the "methods" are represented by snippets. Below, you can find a sample base template extended by the module-specific content:

<?xml version="1.0" ?>
<opt:root>
<!-- base template -->
<html>
<head>
    <title>{$title}</title>
</head>
<body>
<div id="header">
    <opt:insert snippet="header">
        <h1>My website</h1> 
    </opt:insert>
</div>
<div id="content">
    <opt:insert snippet="content">
        <p>Default content</p> 
    </opt:insert>
</div>
</body>
</html>
</opt:root>

And the extending template:

<?xml version="1.0" ?>
<opt:extend file="base.tpl">
    <opt:snippet name="header">
        <h1>My website</h1>
        <h2>My awesome module</h2>
    </opt:snippet>
    <opt:snippet name="content">
        <p>The module-specific content.</p>
    </opt:snippet>
</opt:extend>

Conclusion

Open Power Template 2 brings lots of new features and significant improvements to the predecessor. If you enjoyed OPT 1.x, you will surely enjoy the new version, too.

6.1. OPT 1.x
6. Migration
« Previous
6. Migration
Next »
6.2. PHP