Special-tags

This documentation page describes advanced functions of the framework, that are designed for special application cases of more complex software designs.

Please be aware, that within a tag definition only spaces are allowed as a separator. Tabs or new line characters are not parsed and using them can lead to unrecognized error on tag definition analysis!

1. Iterator

The iterator has been introduces to display lists of objects or associative arrays. The tag definition within a template file defines the output format and the controller delivers the data to display.

1.1. Scheme

The iterator tag's scheme is as follows:

  • The surrounding <html:iterator /> tag defines a re-usable fragment within an APF template . The iterator's behavior is similar to an <html:template /> tag. The latter one is re-usable, too, and is managed by a document controller and utilized to create output. In case the iterator is not told to create it's HTML representation by HtmlIteratorTag::transformOnPlace() or the output of HtmlIteratorTag::transformIterator() is injected into a place holder no output comes up.
  • The <iterator:item /> tag describes a self-repeating element within the iterator. Within this tag you can add any HTML code, place holders and further tags to create output.
  • If required, you may define a <iterator:fallback /> tag to generate an alternative output in case the iterator has received no content. This tag is based on the <html:template /> tag and thus inherits all it's functionality that you might be already familiar wizj.
  • The area within a <html:iterator /> tag and outside of <iterator:item /> you may define any HTML code as well as further place holders and custom tags to generate output.

The definition of the tag is as follows:

APF template
<html:iterator name=""> ... [<html:placeholder name="" />] [<html:getstring namespace="" config="" entry="" />] [<core:addtaglib class="" prefix="" name="" />] ... <iterator:item [getter=""]> ... <html:placeholder name="" /> [<html:getstring namespace="" config="" entry="" />] ... </iterator:item> ... [<iterator:fallback> ... [<html:placeholder name="" />] [<html:getstring namespace="" config="" entry="" />] ... </iterator:fallback>] ... </html:iterator>

Within an <iterator:item /> tags any number of place holders (<html:placeholder />) and HTML elements can be defined.

Description of the attributes:
  • name (1): Name of the iterators. Used to refer to the desired instance with a controller. (Allowed characters: [A-Za-z0-9])
  • getter: Name of the method that is used to retrieve an object's attribute. (Allowed characters: [A-Za-z0-9_])
  • name (2): Name of the place holder. (Allowed characters: [A-Za-z0-9])

Details on the usage of the <iterator:item /> and the <iterator:fallback /> tags are contained in the following chapters.

In order to display language dependent value within the iterator (e.g. for language dependent table headers), the <html:getstring /> tag can be used. If you are not comfortable with this tag, feel free to add your custom tags using the <core:addtaglib /> tag.

1.2. Definition of the data structure

The iterator deals with two kinds of content: associative arrays und object lists. Due to flexibility reasons, it is recommended to use object lists to have more flexibility creating templates within the <iterator:item /> tag (see chapter 1.2.2).

1.2.1. Associative arrays

The iterator is built to handle associative arrays as data structure within an <iterator:item />. Displaying a product list like

APF template
<html:iterator name="products-list-simple"> <h2>Products</h2> <p> The following list contains our products: </p> <ul> <iterator:item> <li> <h3><html:placeholder name="name" /></h3> <img src="<html:placeholder name="img" />" /> <span><html:placeholder name="price" /></span> </li> </iterator:item> </ul> </html:iterator>

the iterator expects you to provide the following data structure:

PHP code
class IteratorTestController extends BaseDocumentController { public function transformContent() { $data = [ [ 'name' => 'Cheap mobile phone', 'price' => '150€', 'img' => 'cheapo.png' ], [ 'name' => 'Mid-range mobie phone', 'price' => '350€', 'img' => 'mid-range.png' ], [ 'name' => 'Premium mobile phone', 'price' => '550€', 'img' => 'premium.png' ] ]; $iterator = &$this->getIterator('products-list-simple'); $iterator->fillDataContainer($data); $iterator->transformOnPlace(); } }
Please note that the iterator expects a numeric list of items where each item contains an associative array containing the content. Associative lists including associative elements are not allowed.

Method fillDataContainer() returns the instance of the iterator that has been defined within the current document and transformOnPlace() tells the iterator to display itself.

All place holders (e.g. <html:placeholder name="name" />) within an <iterator:item /> tag refer to the data structure values. The name of the array key must correspond to the value of the name attribute. Values that are not defined will be replaced by null.

Besides the classic definition of place holders you may want to use the extended templating syntax within an <iterator:item /> tag:

APF template
<html:iterator name="products-list-simple"> <h2>Products</h2> <p> The following list contains our products: </p> <ul> <iterator:item> <li> <h3>${name}</h3> <img src="${img}" /> <span>${price}</span> </li> </iterator:item> </ul> </html:iterator>

Details can be taken from chapter Templates.

Using the extended templating syntax you can also use array access within one loop run as follows:
APF template
<iterator:item> <li> <h3>${item['name']}</h3> <img src="${item['img']}" /> <span>${item['price']}</span> </li> </iterator:item>
The iterator stores the current object within data attribute item for each loop run. Mixing up all three variants (classic place holders, place holders using the extended templating syntax, and array access) is perfectly ok.
1.2.2. Object lists

Accessing object lists is similar to the approach described in chapter 1.2.1. The only difference is the data type that is accessed which can be any type of object.

Displaying a product list like

APF template
<html:iterator name="products-list-objects"> <h2>Products</h2> <p> The following list contains our products: </p> <ul> <iterator:item> <li> <h3><html:placeholder getter="getName" /></h3> <img src="<html:placeholder getter="getImg" />" /> <span><html:placeholder getter="getPrice" /></span> </li> </iterator:item> </ul> </html:iterator>

the iterator expects you to provide the following data structure:

PHP code
class Article { private $name; private $price; private $img; public function __construct($name, $price, $img) { $this->name = $name; $this->price = $price; $this->img = $img; } public function getImg() { return $this->img; } public function getName() { return $this->name; } public function getPrice() { return $this->price; } } class IteratorTestController extends BaseDocumentController { public function transformContent() { $data = [ new Article('Cheap mobile phone', '150€', 'cheapo.png'), new Article('Mid-range mobile phone', '350€', 'mid-range.png'), new Article('Premium mobile phone', '550€', 'premium.png') ]; $iterator = &$this->getIterator('products-list-objects'); $iterator->fillDataContainer($data); $iterator->transformOnPlace(); } }
Please note that the iterator expects a numeric list of items where each item contains an object containing the content. Associative lists including objects are not allowed.

Method getIterator() returns the instance of the iterator that has been defined within the current document and transformOnPlace() tells the iterator to display itself.

All place holders (e.g. <html:placeholder name="name" />) within an <iterator:item /> tag refer to the object values. The name of the method called to retrieve the data is defined with attribute getter of the <iterator:item /> tag. Unknown methods lead to an Exception.

Retrieving an object's attribute can be done in two ways:

  • Using the <iterator:item/> tag you can define a generic method for all place holders. Doing so, you can specify the name of the attribute within the <html:placeholder/> tag using the name attribute. The value of this attribute then refers the object's property to display. Example:
    APF template
    <html:iterator name="..."> <iterator:item getter="getProperty"> <html:placeholder name="DisplayName" /> </iterator:item> </html:iterator>
    Within this mode the tag expects the current object to implement a method like
    PHP code
    public function getProperty($name)
    that returns the value of the property (here DisplayName).
  • Using the extended templating syntax you can also access content of an object within one loop run as follows:
    APF template
    <iterator:item> <li> <h3>${item->getName()}</h3> <img src="${item->getImg()}" /> <span>${item->getPrice()}</span> </li> </iterator:item>
    The iterator provides the current object within data attribute item.
Mixing up the two options (generic getter and object access using the extended templating syntax) are also possible.

1.3. Usage

1.3.1. Definition within template

Within your document controller you can use the following methods to control the iterator:

PHP code
class ListController extends BaseDocumentController { public function transformContent() { // Get iterator from the current document $iterator = &$this->getIterator('...'); // Pass data to the iterator (list of associative arrays or objects) $iterator->fillDataContainer(array( ... )); // Display iterators where it has been defined within the template or ... $iterator->transformOnPlace(); // ... fill a place holder with the output $this->setPlaceHolder('...', $iterator->transformIterator()); } }
1.3.2. Numbering lists

To number entries of a list or of a table you can may want to use a special place holder named IterationNumber within an <iterator:item /> tag. Example:

APF template
<html:iterator name=""> <iterator:item [getter=""]> <html:placeholder name="IterationNumber"> </iterator:item> </html:iterator>

The start position of the counter can be changed within a controller as desired. For this reason, you might want to use HtmlIteratorTag::setIterationNumber() as follows:

PHP code
class ListController extends BaseDocumentController { public function transformContent() { $iterator = &$this->getIterator('...'); $iterator->fillDataContainer(array( ... )); $iterator->setIterationNumber(5); $iterator->transformOnPlace(); } }

Further options on tweaking this option can be taken from chapter 1.3.3 zu Rate.

Defining place holder IterationNumber can be done as classic placeholder using a <html:placeholder /> tag as well as using the extended templating syntax.
1.3.3. Using the pager

Using the iterator in combination with the Pager numbering of lists and tables can be continued on subsequent pages. To do so, the <html:iterator /> tag must be configured with the pager attribute. The value of the attribute refers to a configuration section for the pager.

The following code block makes the iterator expect configuration file /APF/config/modules/pager/{ENVIRONMENT}_pager.ini being set up and containing a configuration section PagerExample:

APF template
<html:iterator name="" pager="PagerExample"> <iterator:item [getter=""]> <html:placeholder name="IterationNumber"> </iterator:item> </html:iterator>
1.3.4. Definition of fallback content

Displaying lists of various types of content somehow always includes displaying a fallback content. This use case can be mastered using the <iterator:fallback /> tag. The content defined within is displayed if the iterator has nothing to display.

There are two options to manage behaviour of the iterator:

  • normal (default): fallback content is displayed in addition to the HTML markup defined within the iterator.
  • replace: alternative content completely replaces all HTML markup.

The mode described above can be set using <html:iterator />'s fallback-mode attribute.

The following code block gives you an example for displaying a product list including an alternative content:

APF template
<html:iterator name="products-list-simple" fallback-mode="replace"> <h2>Products</h2> <p> The following list contains our products: </p> <ul> <iterator:item> <li> <h3><html:placeholder name="name" /></h3> <img src="<html:placeholder name="img" />" /> <span><html:placeholder name="price" /></span> </li> </iterator:item> </ul> <iterator:fallback> <h2>No products available</h2> <p> Unfortunately, there are no products available. Please come back in <html:placeholder name="count" /> days. </p> </iterator:fallback> </html:iterator>

As long as products are available the product list is displayed. Otherwise, the alternative content replaces the list.

Alternative content can be created and managed same as with <html:template /> tags. The following code block gives you an impression how to set the place holder within <iterator:fallback /> to express the number of days customers should wait until their return:

PHP code
class ProductsController extends BaseDocumentController { public function transformContent() { $iterator = $this->getIterator('products-list-simple'); ... $fallback = &$iterator->getFallbackContent(); $fallback->setPlaceHolder('count', '3'); $iterator->transformOnPlace(); } }
1.3.5. Evaluating status variables

For each loop run, the iterator provides status variables. They can be used directly or within custom tags added to an item. All information is contained within the data attribute status containing an instance of APF\tools\html\taglib\IteratorStatus. This class offers the following methods:

PHP code
class IteratorStatus { public function getCssClass() { return $this->cssClass; } public function isFirst($asString = false) { return $asString === false ? $this->isFirst : $this->convertToString($this->isFirst); } public function isLast($asString = false) { return $asString === false ? $this->isLast : $this->convertToString($this->isLast); } public function getItemCount() { return $this->itemCount; } public function getCounter() { return $this->counter; } }

The following list describes how the above methods can be used for output generation:

  • getCssClass(): returns a CSS class tailored to each loop run that can be used for formatting purposes. By default, it returns first for the first entry, middle for every subsequent one, and last for the last element of the list. The names of the CSS classes can be changed by the first-element-css-class, middle-element-css-class, and last-element-css-class attributes of the <html:iterator /> tag to fit your use cases.
  • isFirst(): returns true in case the current element is the first one. Applying optional argument as true it returns no boolean value but a string. This is better for display purposes (e.g. as prefix/suffix of a CSS class) especially in case of returning false.
  • isLast(): returns true in case the current element is the last one. Applying optional argument as true it returns no boolean value but a string. This is better for display purposes (e.g. as prefix/suffix of a CSS class) especially in case of returning false.
  • getItemCount(): returns the total amount of items within the list.
  • getCounter(): returns a sequential number that can be used for labelling purposes.

The following example is designed to display a product list where the status object is used for formatting purposes:

APF template
<html:iterator name="products-list-objects-extended" first-element-css-class="prd-first separator" middle-element-css-class="prd-center" last-element-css-class="prd-last"> <h2>Products</h2> <p> The following list contains our products: </p> <ul> <iterator:item> <li class="${status->getCssClass()}" data-item-count="${status->getItemCount()}" data-is-first="${status->isFirst(true)}" data-is-last="${status->isLast(true)}"> <h3>(${item->getCounter()}) ${item->getName()}</h3> <img src="${item->getImg()}" /> <span>${item->getPrice()}</span> </li> </iterator:item> </ul> </html:iterator>

The corresponding HTML output is as follows (shortened):

APF template
<ul> <li class="prd-first separator" data-item-count="3" data-is-first="1" data-is-last="0"> <h3>(1) Cheap mobile phone</h3> <img src="cheapo.png"/> <span>150€</span> </li> <li class="prd-center" data-item-count="3" data-is-first="0" data-is-last="0"> <h3>(2) Mid-range mobile phone</h3> <img src="mid-range.png"/> <span>350€</span> </li> <li class="prd-last" data-item-count="3" data-is-first="0" data-is-last="1"> <h3>(3) Premium mobile phone</h3> <img src="premium.png"/> <span>550€</span> </li> </ul>
1.3.6. Stacking of iterators

Displaying multi-dimensional lists iterators can be stacked. The following code block defines a two-dimensional data structure with women and men names including two examples each:

PHP code
use APF\core\pagecontroller\BaseDocumentController; class IteratorStackingController extends BaseDocumentController { public function transformContent() { $iterator = $this->getIterator('names'); $iterator->fillDataContainer([ [ 'name' => 'Women names:', 'list' => [ ['name' => 'Maria'], ['name' => 'Theodora'] ] ], [ 'name' => 'Men names:', 'list' => [ ['name' => 'John'], ['name' => 'George'] ] ] ]); } }

In case you want to display the structure with an iterator, you may want to use the following template code:

APF template
<html:iterator name="names" transform-on-place="true"> <ul> <iterator:item> <li> <item:fill-iterator name="examples" data="item['list']"/> (${status->getCounter()}) ${item['name']} <ul> <html:iterator name="examples" transform-on-place="true"> <iterator:item> <li>(${status->getCounter()}) ${item['name']}</li> </iterator:item> </html:iterator> </ul> </li> </iterator:item> </ul> </html:iterator>

The <item-fill-iterator /> tag initializes the iterator the same way fillDataContainer() does but in this case the stacked examples iterator. The tag uses data of the current loop run and injects the data contained in the list attribute into the stacked iterator.

The name attribute of the <item-fill-iterator /> tag refers to the stacked iterator - in this case the examples iterator - and the data attribute is used to evaluate the data set to be injected into the stacked iterator. The syntax follows the extended templating syntax described in chapter Extended template functionality.

The output of the list that is defined within the above controller is as follows:

APF template
<ul> <li> (1) Women names: <ul> <li>(1) Maria</li> <li>(2) Theodora</li> </ul> </li> <li> (2) Men names: <ul> <li>(1) John</li> <li>(2) George</li> </ul> </li> </ul>
Due to the fact that an iterator is controller by a document controller the stacked iterator must define attribute transform-on-place with value true. Otherwise, the iterator will not be displayed!
The implementation described here allows to stack iterators several times. Please ensure that each stacked iterator is properly initialized.

2. Media stream tags

The media stream tags enable the developer to store and deliver GUI ressources directly from the namespace of a specific module. For this reason, the framework contains an abstract implementation of a streaming taglib and several dedicated taglibs, that generate a media url. Further, a generic front controller action is included, that streams the media files, that are requested by the tags.

In order to use the tags you must be sure, that the front controller action, that is intended to deliver the desired files, has a valid configuration for the current context. The action config is expected to be contained in the

Code
/APF/config/tools/media/actions/{CONTEXT}/{ENVIRONMENT}_actionconfig.ini

file. The content of the file can be taken from the following code box:

APF configuration
[streamMedia] ActionClass = "APF\tools\media\actions\StreamMediaAction"

A example configuration file is also included in the apf-configpack-* release file under tools/media/actions/.

The following code box shows an real life application example:

APF template
<html:form name="TestFormular"> <img src="<html:mediastream namespace="APF\modules\mymodule\pres\images" filename="phone_icon.png" />" alt="" /> <form:text name="phonenumber" /> <br /> <form:button name="send" value="Absenden" /> </html:form>

As you can take from the example above, the <html:mediastream /> tag expect the following attributes to be filled:

  • namespace: Namespace to the desired media file. (Allowed characters: [A-Za-z0-9:])
  • filename: Name of the media file. (Allowed characters: [A-Za-z0-9_.-])
If you intend to manipulate the namespace of the file, that should be delivered, because you want to store the image files - using the context to give the application an individual touch - you have to act like this:
  1. Add an id attribute to the desired tag:
    APF template
    <img src="<html:mediastream namespace="APF\modules\mymodule\pres\images" filename="phone_icon.png" id="PhoneIcon" />" alt="" />
  2. Manipulate the namespaces within the responsible document controller:
    PHP code
    class ExampleController extends BaseDocumentController { public function transformContent(){ $mediaStreamTag = &$this->getMediaStreamTagByID('PhoneIcon'); $mediaStreamTag->setAttribute($mediaStreamTag->getAttribute('namespace').'\\'.$this->getContext()); } private function &getMediaStreamTagByID($id){ $children = &$this->getDocument()->getChildren(); foreach($children as $objectId => $DUMMY){ if(get_class($children[$objectId]) == 'MediaInclusionTag'){ return $children[$objectId]; } } throw new InvalidArgumentException('No media stream tag contained within the current document!'); } }
  3. Manipulation of the file name within a template:
    PHP code
    class ExampleController extends BaseDocumentController { public function transformContent() { $FileTemplate = &$this->getTemplate('file'); $mediaStreamTag = &$this->getMediaStreamTagByID('FileIconID', $FileTemplate); $mediaStreamTag->setAttribute('extension', 'png'); $mediaStreamTag->setAttribute('filebody', 'dateinameOhneEndung'); } private function &getMediaStreamTagByID($id, TemplateTag &$template) { $children = &$template->getChildren(); foreach ($children as $objectId => $DUMMY) { if (get_class($children[$objectId]) == 'MediaInclusionTag' && $children[$objectId]->getAttribute('id') == $id ) { return $children[$objectId]; } } throw new InvalidArgumentException('No media stream tag contained within the current template "' . $template->getAttribute('name') . '"!'); } }

The front controller action that is used to deliver the media resources (StreamMediaAction) includes the possibility to explicitly configure allowed file extensions along with their MIME types. Thus, you can add or remove extensions. Within the default setup, the following types are allowed:

  • png or image/png respectively
  • jpeg or image/jpg respectively
  • jpg or image/jpg respectively
  • gif or image/gif respectively
  • css or text/css respectively
  • js or text/javascript respectively

In order to re-define the existing values the configuration file {ENVIRONMENT}_allowed_extensions.ini must be present under APF\tools\media\{CONTEXT}. Within there, you can specify the allowed file extensions as follows:

APF configuration
[Default] jpg = "image/jpg" xml = "text/xml" psd = "application/psd"

3. Generic importdesign tag

Within more complex applications it is often necessary to fill the views - defined with the <*:importdesign /> tags - dynamically. In many cases, the developer thus wants to use model information of the application. To be able, to use the business layer as a real control layer, the framework features a generic importdesign tag, that allows you to retrieve the name of the template to include as well as the template's namespace from the desired application model dynamically.

The tag's signature looks like this:

APF template
<generic:importdesign model-class="" model-mode="NORMAL|SINGLETON|SESSIONSINGLETON" namespace-param="" template-param="" [get-method=""] [dependent-action-namespace="" dependent-action-name="" [dependent-action-params=""]] />

The attributes have the following meaning:

  • model-class: Fully-qualified class name of the model class. (Allowed characters: [A-Za-z0-9_\])
  • model-mode: Creation mode of the model. (Allowed values: NORMAL|SINGLETON|SESSIONSINGLETON)
  • namespace-param: Name of the model param, that returns the namespace of the template. (Allowed characters: [A-Za-z0-9_.-])
  • template-param: Name of the model param, that returns the name of the template. (Allowed characters: [A-Za-z0-9_.-])
  • get-method: Name of the model method, that should be used to query the template name and namespace of the template to include. Please note, that the method must expect one param that is given the value of the namespaceparam or templateparam attributes respectively and the tag expects that the function returns the value of the two parameters. By default, the getAttribute() function is used. (Allowed characters: [A-Za-z0-9_])
  • dependent-action-namespace / dependent-action-name / dependent-action-params: These three options are intended to automatically register an action with the front controller. This functionality is helpful, if a module is included by the tag and a front controller action is used for navigation purposes.
    The attribute dependent-action-namespace defines the namespace of the action (e.g. ACME\site\biz) and dependent-action-name the name or the alias of the action (e.g. Navigate). dependent-action-params contains the params of the action like param1:value1|param2:value2. This format ist already known from the action configuration file layout.

In order to use the tag, you must first add the tag by placing

APF template
<core:addtaglib class="APF\tools\html\taglib\GenericImportTemplateTag" prefix="generic" name="importdesign" />

before the tag definition.

Notes:
  • As an real life application example the Behind the site can be used. This article describes, how this documentation page is implemented and which tools of the framework are used.
  • If a front controller action is used for navigation purposes, the action class must set the class variable $keepInURL to true. This causes the LinkGenerator to include the action and it's params to be included while url generation.
  • The registration of the action is only done, if the dependent-action-namespace and dependent-action-name attributes are present in the tag definition and the action was not registered before. The action params attribute is optional.

4. core:appendnode tag

Within a discussion about reusable template fragments (e.g. forms), the idea occurred to design a taglib, that can import various content to the scope of the current document. Thanks to the generic DOM structure of the GUI elements of the framework, this task is quite easy.

In order to provide a generic and reusable function, the 1.8 branch now features the <core:appendnode /> tag, that can import any content from a defined template. To use the tag, you must provide two attributes similar to the importdesign tag: namespace and template.

Besides, the optional attribute includestatic is available. It can be used to include all the content defined in the included template by setting it's value to true. In case the value contains any other value or the optional attribute is not defined, only the DOM nodes (instances of tags) of the included template are re-located.

4.1. Inclusion of templates

To include reusable fragments, the following code must be placed within the desired template:

APF template
<core:appendnode namespace="..." template="..." [includestatic="true" ] />

If you want to reuse a special template, that is ised to display a domain object of your application, it is suitable to define this tag within a seperate template file (namespace: APF\sites\testsite\pres\templates\generic; template: generic_templates). The tag definition my look like this:

APF template
<html:template name="ReusableTemplate"> ... <html:placeholder name="DisplayName"> ... </html:template>

In order to use the html template within another template file, the fragment can be included using the following tag definitions:

APF template
<core:appendnode namespace="APF\sites\testsite\pres\templates\generic" template="generic_templates" />

4.2. Usage of the imported elements

The usage of the elements imported by the <core:appendnode /> tag is identical to the previous approach. This is because the elements are directly appended to the current children list within the DOM tree. Especially, the document controller's methods (e.g. getTemplate()) can be used as well.

To address the template printed in chapter 4.1, the following code snippet can be used:

PHP code
$tmpl = &$this->getTemplate('ReusableTemplate');

4.3. Important notes

Due to the fact, that template parsing is done identically to the <core:importdesign /> tag.

Further, the tag creates transformation marker tags within the origin template, to enable the transformOnPlace() feature of the included tags supporting this. Please be aware, that the sequence of definition is equal to the marker tag order!

In case you want to include static content of the included template such as

APF template
<div class="formattingContainer"> <html:template name="ReusableTemplate"> ... </html:template> </div>

includestatic must be set to true.

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.