Analyst/Consultant/Coder

05 – Writing custom components for KudzuPHP

The KudzuPHP template engine upon which Kazoo has been built is designed to be flexible and extensible. One of the best features about KudzuPHP is that it is amazingly easy to embed the engine in your PHP applications. Another great feature is that the API is simple so that it is also easy to write all new components and plug them right into the engine without changing any of the original engine code. The KudzuPHP component system is so simple you can be writing your own components within minutes.

To see just how easy it is to write a new component let’s examine a real world example. In this example we are going to study the “IfTrue” tag which is formatted as follows:

<!--{IfTrue|value}--> ... some content ... <!--{/IfTrue}-->

When KudzuPHP processes this tag the following events take place:

First the engine retrieves the tag handler that is assigned to handle the given tag. This is a case insensitive lookup into the engine’s collection of tag handlers. The value that is retrieved is an object which has at the very least a function with the following signature:

function handleTag ($node) { 
    // ... some PHP code here ... 
}

As you can see the basic requirements for creating a new tag handler component is extremely simple. The only parameter passed to a tag handler is a reference to the template node for which it is being invoked. This node contains all the references and functions required to interact with the engine. Let’s flesh out the rest of the object definition that is employed by the IfTrue component and then we’ll explore what happens within the tag handler function.

class CTHIfTrue {
    function handleTag($node) {
        // ... some PHP code ... 
    }
}

Having the code definition around is of no use unless we install an actual instance into the template engine to use and assign it to a specific tag. Here is the code that does that:

$this->setHandler( 'IfTrue', New CTHIfTrue() );

In reality IfTrue is a built in tag handler so the engine does the work of installing an instance of it for you as it does this for every built component. If you were to write your own component you would use your own instance variable rather than ” $this “. This brings up another point – that you can override existing tag handlers by installing new ones using an existing tag.

Thus far we have a perfectly valid component that does absolutely nothing. If we left things this way the component would act just like the Ignore component does. But let’s add functionality to the component and make it live up to its name.

function handleTag($node) {
	if ( !$node->assertParamCount(1,"value") )
		return;
	if ( !$node->getEngine()->getValue( $node->getParamItem(0) ) )
		return;
	$node->stackPush();
	$node->evalNodes();
	$node->stackPop();
}

We know from a previous tutorial that KudzuPHP passes parameters positionally in an array. The parameters are retrieved from node where the template engine found them. The assertParamCount function requires a certain number of parameters to be found or it inserts an error into your output and returns false. The IfTrue component requires you to supply the name of the boolean value you want to examine.

Next the component performs a case insensitive lookup into the engines internal value collection/array and evaluates it as a boolean. If the value is false the component does nothing which is what we’d expect. If however the value is true the component needs to include all the content that fell within its start tag and terminal tag. In case you were wondering the getParamItem function you see takes an optional default value as it’s second parameter. So we could have also made this call:

$param = $node->getParamItem(0,false);

Finally the component responds to the true state and pushes a new slice onto the template engine’s internal output stack, evaluates the content, and pops the resulting output (if any) off the stack and appends it to the previous stack level. KudzuPHP uses an output stack so that any substitution that takes place is performed over the smallest amount of text possible.

Remember that KudzuPHP provides that the content of template tags can contain other tags. Notice that the IfTrue tag does not know or care that the content it is evaluating may or may not have other tags to evaluate – all that is handled by the template engine. Writing custom components for a template engine doesn’t get any easier than this.

I’ll close out this tutorial by including the code for the ” If ” component for your inspection and you can see how to write custom components for KudzuPHP that institute a template hierarchy of their own.

class CTHIfThenElse {
	function handleTag($node) {
		if ( !$node->assertParamCount(1,"value") )
			return;
		$node->stackPush();
		if ($node->getEngine()->getValue($node->getParamItem(0)))
			$node->evalChildNode("Then");
		else
			$node->evalChildNode("Else");
		$node->stackPop();
	}
}

Copyright © 2011. All Rights Reserved.