Enhancement of existing functionality

1. Introduction

I'm sure, every developer was once faced with the situation, that an existing library helped to solve most of the previous tasks, but is not able to handle the current special case. Many developers then tend to implement a completely new function to meet the current case's needs. Others try to convulsively find another library that handles this case. All of these possibilities help you to get the goal, but reduce the maintainability of your software and increase error rate due to a "wild" combination of various external libraries and special functions for several special cases. Furthermore, each developer should keep in mind, that API changes originate changes to every function that uses the libray and is this equal to leaving the update path of the external library. Perhaps, even quick hacks won't work in the next version of the third party library.

This tutorial wants to explain a method to enhance existing functionality without changing the provided library. The tutorial assumes, that the used library is third party code. Otherwise, this method doesn't make sense.

Maybe you now think, that an API change means, that the API was not designed well. In many cases you are right, but there are many APIs, that are not designed to meet every special case of your application.

2. Taglib example

The following example shows you how to enhance the socialbookmark library delivered with each release to meet your demands.

2.1. Problem description

The socialbookmark library contained in each apf-codepack-* release are intended to be included in the content area of your application via XML tag. For this reason, the module includes a taglib, whose characteristics are described on the Socialbookmarking page. The tag definition allows you to specify a page title within the tag definition, that is used as a title when bookmarking the current page. This definition is statically, because it is specified on tag definition time and not on execution time. This is problematically with CMS webpages, because there, titles must be dynamic!

2.2. Analysis of the existing API

To analyze the existing API you must ask yourself the question: "What is already possible and what is really missing?". In case of the socialbookmark module, the answer is quite obvious: static titles are possible, dynamic titles not!

2.3. API extension by wrapping

A very common way of extending a API is to wrap it. Wrapping means, that you build a layer around the existing library - in this case a taglib - to enhance the functionality without changing the library itself.

Let's at first have a look at the existing library. The taglib implements the APFObject's transform() method. Within this function the class passes the necessary attributes to the socialbookmarkManager and asks him to give back the bookmark elements. The source code of the taglib (please refer to the /apps/modules/socialbookmark/pres/taglib folder in the apf-codepack-* release) is displayed in the following code box (comments werde dropped):
PHP code
class SocialBookmarkBarTag extends Document { public function __construct(){ $this->attributes['width'] = '20'; $this->attributes['height'] = '20'; $this->attributes['title'] = null; $this->attributes['url'] = null; $this->attributes['target'] = null; } public function transform(){ // get bookmark manager $sBM = &$this->getServiceObject('modules::socialbookmark::biz','SocialBookmarkBarManager'); // configure width and height $sBM->set('Width',$this->attributes['width']); $sBM->set('Height',$this->attributes['height']); // konfigure URL parameters if($this->attributes['url'] != null){ $sBM->set('URL',$this->attributes['url']); } if($this->attributes['title'] != null){ $sBM->set('Title',$this->attributes['title']); } if($this->attributes['target'] != null){ $sBM->set('Target',$this->attributes['target']); } // return bookmark HTML code return $sBM->getBookmarkCode(); } }

In order to make the title passed to the bookmark service dynamic, ist is well to define another tag library, that only contains the difference of functionality, but uses the existing library. To make it easier to show the proceeding to you, I define, that the tag should be named my:bookmark. The taglib then contains the following source code:

PHP code
import('modules::socialbookmark::pres::taglib', 'SocialBookmarkBarTag'); class MyBookmarkTag extends SocialBookmarkBarTag { public function transform(){ // gather the title of the current page $title = /* current title */; // fill the title attribute, that is used by the parent class $this->setAttributes('title', $title); // generate output with aid of the parent class return parent::transform(); } }

As you can see in the code box above, the transform() only contains the gathering of the page's title. There, the title is assigned to the attributes offset used by the parent class. The core function is still done by the SocialBookmarkBarTag class. Because of the fact, that our wrapper class inherits from SocialBookmarkBarTag, it is still possible to use the

  • width
  • height
  • target

attributes within the tag definition. The following code shows you how to include the new taglib into your templates:

APF template
<core:addtaglib namespace="your::namespace" class="MyBookmarkTag" prefix="my" name="bookmark" /> <my:bookmark width="16" height="16" />

Details on tag implementation can be found under Implementation of tags.

2.4. Update handling

In case of API changes to the third-party library, adaptation to the new API is limited to filling the attribute title, because the call of the parent transform() is still the same. A second advantage is, that the API of the wrapper class MyBookmarkTag remains the same and the components using the API of the wrapper class must not be changed. The example described in the present tutorial only contained the enhancement of taglibs, but this principle can be adopted to any other domain.


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.