Templates in Depth

There are many content management systems out there and even more frameworks. Most have a template system, usually a simplified programming language to allow people with no programming skills to implement their own designs. These template languages are very limited in scope and thus easy to learn. But when you learn more about the framework, the template language starts to show its limits. To go any further you will need to learn another language, the one in which the framework or system was written.

Now you find yourself in a whole new world where nothing is recognizable. The language is unknown and complex and the concepts in the code are very unfamiliar. This is a leap that most people cannot make.

Instead Ariadne takes a different approach. Templates are not a simplified system to allow designers some degree of control. To a very large extent they are the system. Almost all code in Ariadne is written as a template and the template language is PHP—or something almost like it.

A simple view.html template could look like this:

<!doctype html>
<html>
<body>
<h1><pinp> echo $nlsdata->name; </pinp></h1>
<pinp>
echo $nlsdata->summary;
</pinp>
</body>
</html>

You can call other templates as well. This makes it possible to create sets of templates that together build the full web page.

<pinp>
ar::call('view.head.html');
ar::call('view.header.html');
ar::call('view.body.html');
ar::call('view.footer.html');
</pinp>

And you can define multiple templates with the same name, but for different types of content. This allows for class-based inheritance and polymorphism. Ariadne provides a default set of content types with a predefined inheritance tree. This can be extended with runtime defined faux classes called ‘subtypes’.

In addition you can get or list other content objects and call templates on those, using a file-system like API.

<pinp>
ar::get('some/object/')->call('template.html');
ar::ls()->call('show.html');
</pinp>

Or search for objects using Ariadne’s query language.

<pinp>
ar::find('text.value~="%example%"')->call('show.result.html');
</pinp>

A template in Ariadne can be used like a method on a class in PHP would be. Ariadne has predefined classes for all content in the content tree. You can create multiple templates with the same name for different classes. Again, just like methods. This means you can create a ‘view.body.html’ template for a default page, for an image gallery or for a newspaper. Each knows how to display its own content and all you need to do to build a complex website is to create objects with the correct class in a filesystem.

Templates can be bundled into libraries and be re-used as well. A library is just an object in Ariadne’s content tree where templates are defined. You can include or load a library from anywhere, by calling the loadLibrary() method.

<pinp>
loadLibrary('crumbs', '/system/lib/ariadne/crumbs/');
ar::call('crumbs:crumbs.view.html', array(
'crumbsRoot' => ar('store')->currentSection()
) );
</pinp>

But if you need a library in multiple templates, or just want to manage the libraries in a central place, you can also load all libraries in the config.ini template. This template is always automatically called whenever an object is first loaded from the store ( Ariadne’s name for the database. ) For any object to load, its parent object must be loaded as well. So if you call loadLibrary() in a config.ini template on any object, all its children objects — and the templates run on it—will have access to that library as well.

In addition, you can also load a library unnamed. This means that you don’t need to add the ‘crumbs:’ part like the example above. It also means that the templates can be called directly in the URL. You can make a library that defines the layout of a website or the main functionality of a web application. And you can re-use it in other projects.

psite::config.ini
<pinp>
loadLibrary( 'crumbs', '/system/lib/ariadne/crumbs/');
loadLibrary( ARUNNAMED, '../system/layout/default/');

$arConfig = ar::getvar('arConfig');
$arConfig['settings'] = array(
'site' => $path,
'siteURL' => ar('loader')->makeURL(),
'graphicsURL'
=> ar('loader')->makeURL('',false,false).'graphics/'
);
return $arConfig;
</pinp>

Here a config.ini template is defined on a Site object. A site object may contain a base URL setting that is used to generate URLs for child objects relative to the site object. This way you can manage multiple sites in Ariadne, each with its own domain name or other base URL.

This config.ini template is only run on the site root object and makes sure a default layout library is loaded. It also configures a few settings that can then be used by the layout library templates. This way the layout library is fully re-usable and not tied to a specific website.

You can create many similar looking websites, simply by loading the same layout library in each. They do not have to be exactly the same. You can load extra libraries. Any library loaded unnamed can override templates in any unnamed library loaded earlier. Each template in an unnamed library can thus be customized for a specific situation. You can view each template as a ‘slot’ in a generic framework — something to fill in or override. Except the framework is built using the exact same tools and you can create your own framework with the same simple mechanism.

When used like this, you will sometimes need to call the original template that you are overriding. Ariadne provides a simple method for this:

<pinp>
call_super();
// do something extra here
</pinp>

call_super() calls the next template in the chain with the same name. This can be a template in the same library but for a parent class, or it can be a template in a previous library. call_super automatically passes on all the arguments given to the current template and returns the result from the ‘super’ template.