Templates

1. Definition of templates

The Adventure PHP Framework (APF) uses several meanings of template:

  • Templates are the basis of the HMVC pattern implementation of the Page controller. This component creates a DOM structure using template files (HTML files) or tags and enables the developer to dynamically create the surface of a website or an application according to the requirements.
  • Besides, templates are often referred to as re-usable elements within template files. A common representative is the <html:template /> tag that can be used to realize conditional output or to display repetitive content within template files.

The definition of the MVC pattern describes the meaning of model, view, and controller. The HMVC pattern defines a hierarchical structure of MVC DOM elements that is created based on template content. The Page controller uses the information that are contained within the template files and created child nodes within the current node.

Each template, or each node of the HMVC DOM tree respectively, may define a (Document-)Controller according to the definition of the MVC pattern.

2. Content of templates

Template files typically contain three types of content:

  • APF tags (e.g. <html:placeholder />)
  • HTML code (e.g. <p>...</p>)
  • Any text

Tags are XML tags that are known to the APF parser such as <prefix:name />. They can define any number of attributes - e.g. attribute="value". Explicitly closing tags may contain further tags or simple textual content.

HTML code and any kind of text can be used to fill the content of your web site or application and are not treated by the APF parser. Thus, you can use both as content of attributes and tags.

Please be aware that HTML code within tag attributes can only be processed in case there are no quotes (").

Within APF tags any kind of HTML code can be placed as long as the code does not interfere with the nested tag structure.

Details on the APF parser can be read about under Implementation of tags.

2.1. Template files

Template files are used within the Adventure PHP Framework to create the UI of a web site or application and the Front controller is always started with an initial template.

Within template files APF tags (see Standard taglibs), HTML code or any kind of text can be placed. In most cases the template - e.g. the initial template - contains the basic frame of a web site or an application and defines place holders for dynamic content or includes further templates. Displaying dynamic content, each template may define a (Document-)Controller that is executed on transformation.

The following code box contains the basic frame of a web site:

APF template
<@controller class="VENDOR\pres\controller\MainController" @> <!DOCTYPE html> <html> <head> <title><html:placeholder name="title" /></title> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> </head> <body> <header> <h1><html:placeholder name="title" /></h1> <core:importdesign namespace="VENDOR\pres\templates" template="navi" /> </header> <div id="content"> <core:importdesign namespace="VENDOR\pres\templates" template="content" /> </div> <footer> <core:importdesign namespace="VENDOR\pres\templates" template="footer" /> </footer> </body> </html>

The above template defines two place holder tags that are filled by the MainController and includes further templates using three <core:importdesign /> tag that take care of navigation, content, and footer.

A list of known tags can be found under Standard taglibs or Special-tags respectively. The Implementation of tags tutorial describes how to create custom tags and functions for your web site or application.

2.2. HTML templates

HTML templates are used to define reusable HTML fragments to display conditional content or to create lists. It is recommended to create one template per element that can be used by the controller. HTML templates are not automatically displayed where they are defined but are structural elements that are used to generate content.

The following code box shows an HTML template that is used to create a dynamic table:

APF template
<@controller class="VENDOR\pres\controller\ListController" @> <table> <thead> <tr> <td>Frage</td> <td>Antwort</td> </tr> </thead> <tbody> <html:placeholder name="table-rows" /> </tbody> </table> <html:template name="table-row"> <tr> <td><template:placeholder name="question" /></td> <td><template:placeholder name="answer" /></td> </tr> </html:template>

The template itself contains the frame of the table and the <html:template /> tag defines one line of the table. Generating the content the following controller can be used:

PHP code
use APF\core\pagecontroller\BaseDocumentController; class ListController extends BaseDocumentController { public function transformContent() { $row = $this->getTemplate('table-row'); $buffer = ''; foreach ($this->getItems() as $item) { $row->setPlaceHolder('question', $item->getQuestion()); $row->setPlaceHolder('answer', $item->getAnswer()); $buffer .= $row->transformTemplate(); } $this->setPlaceHolder('table-rows', $buffer) } /** * @return FaqEntry[] */ private function getItems() { ... } }
Templates that are not used for list generation or for repetitive content can be displayed directly where they are defines. For that reason, please use transformOnPlace() within your document controller. Example:
PHP code
class MainController extends BaseDocumentController { public function transformContent(){ $tmpl = &$this->getTemplate('template-name'); $tmpl->transformOnPlace(); } }

In order to simplify display of lists you may want to directly fill place holders. Fur this reason, you can combine two features: the third parameter of the setPlaceHolder() method allows to append content to a place holder and the TemplateTag supports direct output generation implementing the __toString()-Method which internally transforms the template.

The controller implementation can be rewritten as follows:

PHP code
use APF\core\pagecontroller\BaseDocumentController; class ListController extends BaseDocumentController { public function transformContent() { $row = $this->getTemplate('table-row'); foreach ($this->getItems() as $item) { $row->setPlaceHolder('question', $item->getQuestion()); $row->setPlaceHolder('answer', $item->getAnswer()); $this->setPlaceHolder('table-rows', $row, true); } } /** * @return FaqEntry[] */ private function getItems() { ... } }

3. Extended templating

Please note, that the feature described within this article is available with release 2.1!

In addition to the functionality described in chapter 2 you may also want to use dynamic template expressions within APF templates. They provide a shortcut for place holders such as <html:placeholder /> as well as a pseudo language to access data attributes of APF DOM nodes. Besides, method calls and array access of data attributes is possible.

The follwing chapters describe both features and give hints on using them within your application.

3.1. Place holders

Besides the well-known APF tags for place holders such as the

APF template
<html:placeholder name="foo" />

you may also want to use the shorthand version

APF template
${foo}

It helps to reduce size of your templates and potential solves issues with IDE support for HTML files.

The short version of the place holders are constructed by start symbol ${, followed by a unique identifier and closing symbol }. The name must not contain further brackets. Allowed are upper case and lower case letters as well as hyphens and underlines.

Accessing place holders in shorthand writing is the sam as for usual place holders. In case you want to fill the place holders in template

APF template
<@controller class="VENDOR\..\controller\SampleController" @> <div class="${css-class}"> <p> ${intro-text} </p> <p> ${detail-text} </p> <p> <a href="${link-target}">${link-label}</a> </p> </div>

you can use the following controller code for that:

PHP code
namespace VENDOR\..\controller; use APF\core\pagecontroller\BaseDocumentController; class SampleController extends BaseDocumentController { public function transformContent() { $model = $this->getModel(); $this->setPlaceHolder('css-class', $model->getCssClass()); $this->setPlaceHolder('intro-text', $model->getIntroText()); $this->setPlaceHolder('detail-text', $model->getDetailText()); $this->setPlaceHolder('link-target', $model->getMoreLink()->getTarget()); $this->setPlaceHolder('link-label', $model->getMoreLink()->getLabel()); } /** * @return ContentModel */ private function getModel() { return new ContentModel(); } }

3.2. Object access

The pseudo templating language of the APF allows you to access data attributes of APF DOM nodes with dynamic expressions and to print the content that is stored there within templates.

The template example described in chapter 3.1 can be simplified using the pseudo language as follows:

APF template
<@controller class="VENDOR\..\controller\SampleController" @> <div class="${news->getCssClass()}"> <p> ${news->getIntroText()} </p> <p> ${news->getDetailText()} </p> <p> <a href="${news->getMoreLink()->getLinkTarget()}"> ${news->getMoreLink()->getLinkLabel()} </a> </p> </div>

The controller is also reduced by several lines:

PHP code
namespace VENDOR\..\controller; use APF\core\pagecontroller\BaseDocumentController; class SampleController extends BaseDocumentController { public function transformContent() { $this->setData('news', $this->getModel()); } /** * @return ContentModel */ private function getModel() { return new ContentModel(); } }

Using this approach repetitive code can be thrown out of controllers and clarity improves.

Basis for the pseudo template language is the APF DOM model. It allows - similar to HTML nodes - to define data attributes. Class Document therefor provides setData() andgetData(). Within a class derived from BaseDocumentController you can use methods with the same name to access data attributes of the current DOM node.

The subsequent chapters describe the different features of the template language in detail.

3.2.1. List access

Using thepseudo template language of the APF you can access lists similar to the PHP syntax. You may both declare simple and multi-level arrays with numeric and/or alphanumeric offsets.

Within templates you can access simple or nested lists with simple content or even lists with complex content (objects). If necessary, access to complex content requires further interaction. Please refer to chapter 3.2.2 and chapter 3.2.3 for more information.

The following code box contains different list access types for templates:

APF template
<@controller class="VENDOR\..\controller\SampleController" @> <!-- Access to the first numeric offset --> ${news[0]} <!-- Access to the offset xyz --> ${news['xyz']} <!-- Access to the numeric offset 1 and within that list to numeric offset 2 --> ${news[1][2]} <!-- Access to the numeric offset 1 and within that list to the alphanumeric offset xyz --> ${news[1]['xyz']} <!-- Access using mixed offset declarations --> ${news[1][2][3][4]} ${news[1]['two'][3]['four']}

To be able to use the expressions to access data the DOM node has to be added the respective data with the controller first:

PHP code
namespace VENDOR\..\controller; use APF\core\pagecontroller\BaseDocumentController; class SampleController extends BaseDocumentController { public function transformContent() { $model = $this->getModel(); // Access to the first numeric offset $this->setData( 'news', array( 0 => $model ) ); // Access to the offset xyz $this->setData( 'news', array( 'xyz' => $model ) ); // Access to the numeric offset 1 and within that list to numeric offset 2 $this->setData( 'news', array( 1 => array( 2 => $model ) ) ); // Access to the numeric offset 1 and within that list to the alphanumeric offset xyz $this->setData( 'news', array( 1 => array( 'xyz' => $model ) ) ); // Access using mixed offset declarations $this->setData( 'news', array( 1 => array( 2 => array( 3 => array( 4 => $model ) ) ) ) ); $this->setData( 'news', array( 1 => array( 'two' => array( 3 => array( 'four' => $model ) ) ) ) ); } /** * @return ContentModel */ private function getModel() { return new ContentModel(); } }
In case the list elements implement the __toString() method output can be generated directly by list access without any further method calls.
3.2.2. Object access

Besides accessing lists the pseudo template language of the APF offers access to objects of data attributes. The syntax follows the PHP syntax as well.

Method calls of any number and kind can be constructed as well as being mixed with list access. For array access syntax, please refer to chapter 3.2.3.

The following code box shows some examples of method calls:

APF template
<@controller class="VENDOR\..\controller\SampleController" @> <!-- Call to the getCssClass() method of the ContentModel class --> ${news->getCssClass()} <!-- Call to the getLinkLabel() method of the LinkModel class returned by a call to getMoreLink() of class ContentModel --> ${news->getMoreLink()->getLinkLabel()}

To be able to use the expressions to access data the DOM node has to be added the respective data with the controller first:

PHP code
namespace VENDOR\..\controller; use APF\core\pagecontroller\BaseDocumentController; class SampleController extends BaseDocumentController { public function transformContent() { $this->setData('news', $this->getModel()); } }
3.2.3. Combined access

Array access syntax described under chapter 3.2.1 and method call syntax under chapter 3.2.2 can be combined to more complex expressions. For instance, you can combine an array access and one or more method calls to access the data of a list and their items very easily.

Please note, that multiple method calls or list access calls must be separated by ->.

In case you intend to print the first three news entries you may want to use the following template:

APF template
<@controller class="VENDOR\..\controller\SampleController" @> <ul class="news-list"> <li>${news[0]->getIntroText()}</li> <li>${news[1]->getIntroText()}</li> <li>${news[2]->getIntroText()}</li> </ul>

The controller to create the output is as follows:

PHP code
namespace VENDOR\..\controller; use APF\core\pagecontroller\BaseDocumentController; class SampleController extends BaseDocumentController { public function transformContent() { $this->setData('news', $this->getNews()); } /** * @return ContentModel[] */ private function getNews() { ... } }

Method getNews() returns a list of ContentModel instances.

The implementation of the pseudo template language allows further combinations of expressions:

APF template
<!-- Call to getBar() on the third element returned by getFoo() --> ${news->getFoo()->[3]->getBar()} <!-- Call to getBaz() on the result of a getBar() call that is stored in offset foo of the 5th element of data attribute news --> ${news[5]['foo']->getBar()->getBaz()}
Please note, that the examples listed here require a corresponding data structure. Erroneous expressions will lead to errors and thus break application execution.

Comments

Do you want to add a comment to the article above, or do you want to post additional hints? So please click here. Comments already posted can be found below.
There are no comments belonging to this article.