User specific taglibs

1. Introduction

The present page controller implementation creates a DOM tree while parsing templates. The functionality of each DOM node is defined within a taglib class. These taglib classes are based on the class Document that inherits from the central class coreObject. The class Document features the central parser method __extractTagLibTags() that searches a template file for known taglibs. Every XML tag generates another child node of the current DOM node. The XML attributes are added to the attribute list of the taglib implementation so that the taglib class can make use of them.

2. Structure of a taglib

Every XML tag listed under Standard taglibs is represented by a taglib class. This class implements the interface methods defined in the class Document or coreObject respectively.

Every taglib class name must contain the part "_taglib_" between the prefix and the class description. If the developer is likely to introduce the XML tag

APF-Template
<shop:basket />
to one of the templates, the taglib class must be named
PHP-Code
shop_taglib_basket

The part of the name that is marked with green color is called prefix the blue one is named class. Both parts can be choosen freely. Though it is recommended to structure the tags according to their dependency. Given the fact that the <shop:basket /> tag contains various subtags these subtags should have the prefix basket. The following example shows this naming convention:

APF-Template
<shop:basket> <basket:title /> <basket:products> <products:listing /> <products:sum /> </basket:products> </shop:basket>

The example implies, that during parsing of the <shop:basket /> tag, the subtags should be parsed into child DOM objects, too. For this reason the constructor of the taglib implementation of the shop_taglib_basket must contain the definition of the known subtaglibs:

PHP-Code
class shop_taglib_basket extends Document { function shop_taglib_basket(){ $this->__TagLibs[] = new TagLib('namespace::to::taglib','basket','title'); $this->__TagLibs[] = new TagLib('namespace::to::taglib','basket','products'); } [..] }

Same rule applies for the implementation of the <basket:products /> tag (taglib class basket_taglib_products). Here the constructor must declare the tags <products:listing /> and <products:sum />.

2.1. Class member variables

During parsing of the XML / HTML code within the template files known tags will be mapped to DOM objects. The content of the

APF-Template
<php:hightlight> $var = 'value'; </php:hightlight>

tag will be stored in the private class member variable $this->__Content. The attributes of the tag are stored in the associative array $this->__Attributes. Due to that behavior the developer can access the attributes and content of the tag easily and the tags can be configured using XML / HTML attributes. Another advantage is that the tags can be configured with any attributes such as "class" or "style". This lightens the formating of UI elements such as text fields or buttons independent of the PHP code.

The private member variable $this->__ParentObject stores the reference to the parent object of the current node. Due to the fact, that the parent object inherits from coreObjects, using the methods get(), set(), getAttribute() and setAttribute() can be used to gather properties of the parent class instance. The public methods getByReference() and setByReference() allows to get access to any object within the DOM tree. The detailed documentation of these methods can be seen in the API documentation. Here the classes Document and coreObject are importent.

2.2. Class methods

To implement functionality to a present taglib class there are several interface methods that are executed concerning a special page controller timing model. These functions have different meaning, too. Beside the interface methods, the developer can design the class methods freely. Please attend to the following points:

  • Class declaration:

    Each taglib class must inherit from the Document class, because this class is the interface class that serves the central parser method. The class name depends on the XML tag name as described above. To have an XML tag that is named "php:highlight", the first part of the name (prefix) must be "php", the middle part the common string "_taglib_" and the XML class string is "highlight". This leads to the taglib class namephp_taglib_highlight. If this taglib is announced using the <core:addtaglib /> tag the parser searches for this tag in the currend template file. Moreover, it is important that the file name is identical to the class name.

  • Constructor:

    The constructor is intended to contain initializing of member variables or things like that. The constructor is given no argument. When no inizializing must happen there must not be a constructor.

    In common the constructor should be uses to define known taglibs to the current DOM node, that are added as child nodes during DOM construction (see example above). For a detailed implemenation example, please consult the API documentation for the class html_taglib_template or html_taglib_form.

  • onParseTime() implemenation:

    The methode onParseTime() is executed by the page controller when the properties

    • $this->__Context
    • $this->__Attributes
    • $this->__Content
    • $this->__Language

    are set. At this time the taglib class has access to it's attributes and content and operations concerning this properties can be implemented. During execution of the method the node is not added to the DOM tree yet. If the developer must be able to access father or child nodes the function onAfterAppend() should be taken instead.

    This method is ideal for extracting subtags or extracting document controller definitions. Therefore the private methods __extractTagLibTags() and __extractDocumentController() are present due to the fact, that each taglib inherits from the Document class. For details on this two methods please refer to the API documentation.
    To preserve the position, a taglib was defined at and to ensure, that the transformed content is displayed at the correct position, the __extractTagLibTags() method creates place holer tags within the content of a taglib. The pattern of the place holders is:
    APF-Template
    <{OBJECT_ID} />
    Thereby, {OBJECT_ID} is equal to the content of the class member $this->__ObjectID and the array offset where the child nodes are stored ($this->__Children). The place holders can be used during transformation and content placement of the transformed child tags.
  • onAfterAppend() implementation:

    As all children of the currend DOM node are added to the DOM tree the method onAfterAppend() is executed on them. At this moment a DOM node can access every neighbour node by the $this->__ParentObject or $this->__Children member variable. As mentioned above the methods get(), set() and so an grant access to the attributes of these neighbour nodes.

  • transform() implementation

    The methods discussed above all are used to generate and process a DOM tree out of XML / HTML code. The function transform() is to produce XML / HTML code out of the object tree instead. Merely the implementation of the class Document can be taken for a newly created taglib class. For special purpose this method must be overridden be be present class. To generate an attribute string out of the attributes of the current node, the method __getAttributesAsString() can be taken.

In case, the transform() method is overridden within your custom taglib, the developer is himself responsible to transformation of the child nodes. This can possibly done by adding
PHP-Code
foreach($this->__Children as $objectId => $DUMMY){ $this->__Content = str_replace( '<'.$objectId.' />', $this->__Children[$objectId]->transform(), $this->__Content ); }
to your transform() method. Please note, that this does only work, of you have called the __extractTagLibTags() function in either the onParseTime() or the onAfterAppend().

3. Examples

3.1. Taglib php_taglib_hightlight

As already mentioned above the following example describes how to highight and colorize the string between the tags

APF-Template
<php:highlight> [..] </php:highlight>

The implementation of this task is taken over by the class php_taglib_hightlight. For this reason the method transform() is added to the class to modify the content contained in the property $this->__Content with aid of the highlight_string() PHP function. The code box shows how the class must look like:

PHP-Code
class phpphp_taglib_highlight extends Document { function phpphp_taglib_highlight(){ } function transform(){ // count lines $LineCount = substr_count($this->__Content,"\n") - 1; // highlight source code // - Remove new lines at the beginning // - Remove new lines and blanks at the end // - Remove new lines and blanks around the whole text $HighlightedContent = highlight_string(trim('&lt;?php '.ltrim(rtrim($this-&gt;__Content),"\x0A..\x0D").' ?&gt;'),true); // replace php start tags $HighlightedContent = str_replace('&lt;font color="#007700"&gt;&lt;?&lt;/font&gt;','',$HighlightedContent); $HighlightedContent = str_replace('&lt;font color="#0000BB"&gt;&lt;?php&nbsp;','&lt;font color="#0000BB"&gt;',$HighlightedContent); $HighlightedContent = str_replace('&lt;font color="#0000BB"&gt;php','&lt;font color="#0000BB"&gt;',$HighlightedContent); $HighlightedContent = str_replace('&lt;font color="#0000BB"&gt;&nbsp;&lt;/font&gt;','',$HighlightedContent); // enhancement to the PHP5 support $HighlightedContent = str_replace('&lt;span style="color: #0000BB"&gt;&lt;?php&nbsp;','&lt;span style="color: #0000BB"&gt;',$HighlightedContent); $HighlightedContent = str_replace('&lt;span style="color: #0000BB"&gt;&lt;?php','&lt;span style="color: #0000BB"&gt;',$HighlightedContent); $HighlightedContent = str_replace('&lt;span style="color: #0000BB"&gt;?&gt;&lt;/span&gt;','',$HighlightedContent); // replace php end tags $HighlightedContent = str_replace('&lt;font color="#0000BB"&gt;?&gt;&lt;/font&gt;','',$HighlightedContent); // return div enclodes source code with height limit if necessary if($LineCount &gt; 27){ return '&lt;div class="phpcode" style="height: 400px; overflow: auto;"&gt;'.$HighlightedContent.'&lt;/div&gt;'; } else{ return '&lt;div class="phpcode"&gt;'.$HighlightedContent.'&lt;/div&gt;'; } } }

3.2. Taglib html_taglib_entityencode

The taglib html:entityencode provides a basis to convert text into HTML entities. This functionality can be used to encode e-mail addresses to protect them from getting crawled and used for spam. To provide this feature a new taglib class must be created using the method encodeCharactersToHTML of the class stringAssistant to do the encoding. After announcing the taglib via

APF-Template
<core:addtaglib namespace="path::to::namespace" prefix="html" class="entityencode" />
the XML tag can be used as follows:
APF-Template
<html:entityencode>nobody@example.com</html:entityencode>
The source code of the web page delivered may then contain the following HTML code:
APF-Template
&#110;&#111;&#98;&#111;&#100;&#121;&#64;&#101;&#120;&#97;&#109;&#112;&#108;&#101;&#46;&#99;&#111;&#109;

Since the core functionality is not included in the taglib class itself this operation can be reused in components like guestbook controllers. The code box shows how the class must look like:

PHP-Code
import('tools::string','stringAssistant'); class html_taglib_entityencode extends Document { function html_taglib_entityencode(){ } function transform(){ return stringAssistant::encodeCharactersToHTML($this->__Content); } }

3.3. Taglib doc_taglib_createobject

Giving another example the taglib <doc:createobject /> may be described here. This taglib is used to generate the content of this documentation page taking care of the choosen language and the content included there. The content is read from HTML files containing pure text, HTML code and XML strings that give advice to the page controller to include special modules. During parsing the source code is scanned to find known taglibs and new child nodes are created if a known taglib is found. To use this taglib it must be announced by using

APF-Template
<core:addtaglib namespace="tools::html::taglib" prefix="doc" class="createobject" />
After that (directly after) the taglib can be used as follows:
APF-Template
<doc:createobject requestparam="Seite" defaultvalue="Startseite" />

Taking a closer look into the source code the following logic is encapsulated there:

PHP-Code
import('tools::request','RequestHandler'); class doc_taglib_createobject extends Document { function doc_taglib_createobject(){ parent::Document(); } function onParseTime(){ // get tag attributes $RequestParameter = $this->__Attributes['requestparam']; $DefaultValue = $this->__Attributes['defaultvalue']; // initialize request params $_LOCALS = RequestHandler::getValues(array($RequestParameter => $DefaultValue)); // gather current param value $CurrentRequestParameter = $_LOCALS[$RequestParameter]; // fill the content of the tag $this->__Content = $this->__getContent($CurrentRequestParameter); // extract tags $this->__extractTagLibTags(); // check for document controller $this->__extractDocumentController(); } function __getContent($Page){ $File = './frontend/content/c_'.$this->__Language.'_'.strtolower($Page).'.html'; if(!file_exists($File)){ $File = './frontend/content/c_'.$this->__Language.'_404.html'; } return file_get_contents($File); } }
  • At the beginning of the file the RequestHandler is imported to be used later on.
  • The constructor of the taglib calls the constructor of the parent class. This results in the availability of the known taglibs, that are defined in the constructor of the Document class. Each taglib is defined in the member variable $this->__TagLibs in form of the TagLib object. This array is used by the parser to extract the known taglibs. Please note that only known taglibs are found!
  • The method onParseTime() is used to read the tag attributes and get the request parameters with aid of the RequestHandler to configure the tag. After that the content of the desired file is read using the private function __getContent() and filled into the content property. If done so the parser method __extractTagLibTags() is called to generate the document tree out of the known taglibs contained there. Moreover calling the __extractDocumentContoller() tries to find a document controller definition in the present content file.
  • Within the method __getContent() the content of the specified file is read from the folder ./frontend/content and given back at the end of the function. If the desired file is not found the content of a predefined error file is returned.

For continuing application examples the form taglibs can be studied. This taglib classes are stored in the apps/tools/form/taglib/ folder.

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.