Location: PHPKode > scripts > TemplateHandler > templatehandler/templatehandler.php
<?
class TemplateHandler {

	/*
	This are the internal attributes of the class
	*/

    var $Tokens=array(); 		// The values placeholders, which are in the form %NAME%. These belongs to main template
    var $SectionTokens=array(); // Iteration Tokens. These are also in %NAME% format, but belongs to iteration sections into the template
    var $TemplateName; 			// The template's filename
    var $TemplateContent; 		// The template content after it was processed
    var $RawTemplate;			// The raw content, before processing
    var $Sections;				// Sections enable/disable indicators.
    var $Hiddens=array();		// Exclusive show/hide sections
	
	/*
	The constructor method.
	This method receives only one parameter, the template name. If not provided, it will try to fetch a template named as the PHP script
	but with .tpl extension. By now, all templates must reside inside a folder named "templates" below the script's folder.
	*/
    
	function TemplateHandler($tpl_name="") {

		/*
		Did the calling script provided a template name?
		*/	
		if (empty($tpl_name))
			/* No, so we'll figure out the template's name */
			$this->TemplateName=basename($PHP_SELF,".php");
		else
			// Yes!!! We'll try to use the name given to us.
			$this->TemplateName=$tpl_name;
			
		// Add .tpl extension. It's very important to remember not to include the extension when creating an instance of the class.
		// Example:
		// $myIntance = new TemplateHandler("template") <<<=== This is OK
		// $myIntance = new TemplateHandler("template.tpl") <<<=== This is WRONG
		$this->TemplateName.=".tpl";
	
		// If the template we try to use doesn't exists, we'll use a common one.
		// No check on common template about existence.
		if (!file_exists("templates/".$this->TemplateName)) $this->TemplateName="common.tpl";
		
		// Get the raw content. 
		$this->RawTemplate=implode("",file("templates/".$this->TemplateName));
		
    }
    
	/*
	Method SetToken.
	This method takes two parameters: The token NAME and the Value.
	Example:
	$myInstance->SetToken("AUTHOR_NAME","Daniel Marjos");
	$myInstance->SetToken("BORN","08/19/1970");
	$myInstance->SetToken("HOBBIES","Read a lot, mess up with PHP");
	*/
    function SetToken($token_name,$token_value) {
		// We simply make $token_name become a key into Tokens array.
		$this->Tokens[$token_name]=$token_value;
    }
    
	/*
	Method: SetDetailToken
	This method takes two parameters. Section Name and an associative array of tokens=>value pairs. 
	Example:
	$myInstance->SetDetailToken("PublishedClass",array(
		"CLASS_NAME"=>"clsSendMail",
		"PUBLISHED"=>"2003",
		"DESCRIPTION"=>"A simple class for sending mails"
	));
	$myInstance->SetDetailToken("PublishedClass",array(
		"CLASS_NAME"=>"classHTML",
		"PUBLISHED"=>"2003",
		"DESCRIPTION"=>"A simple class for creating HTML content"
	));
	$myInstance->SetDetailToken("PublishedClass",array(
		"CLASS_NAME"=>"clsCoffee",
		"PUBLISHED"=>"????",
		"DESCRIPTION"=>"A simple class for getting my breakfast from a web site"
	));
	*/
    function SetDetailToken($detail_section,$detailValues) {
		$this->Sections[$detail_section]=true; // As long as we set any value to our section, we enable it
		$this->SectionTokens[$detail_section][]=$detailValues; // We set the detail records for the section
    }

	/*
	Method SectionStatus.
	This method sets the section status (pretty obvious, uh?) indicating the class when to show or not the iterative part of the template.
	Useful for master/detail templates, when we haven't records to you on the detail
	
	Example:
	$myInstance->SectionStatus("PublishedClass",true); (or false if we haven't any published class)
	*/
    function SectionStatus($section,$status) {
		$this->Sections[$section]=$status;
    }
    
	/*
	Method HideElement.
	This class has only three special "tags" which are processed.
	Two of them are exclusive, ### and ///
	Here is a portion of a template:
	
	..........
	..........
	..........
	###Identifier
	When "Identifier" is true, this part is not shown 
	###
	///Identifier
	When "Identifier" is true, this part is shown
	///
	..........
	..........
	..........
	
	So, when we have two related parts of our template, and only one of them must be shown at a time,
	we can set Identifier true (hidden) and the portion surrounded by ###identifier (...) ### will be hidden from final result,
	and ///Identifier (...) /// will be shown.
	*/
    function HideElement($element,$hidden) {
		$this->Hiddens[$element]=$hidden;
    }

	/*
	Method SplitTemplate (private)
	Takes three parameters, StartTag, Identifier and EndTag.
	This method is used only to iterations (just by now, in version 2.0 will be used for all kind of open/close tags)
	Returns an assosiative array in the form:
	[left]="all template's code before startTag"
	[middle]="template's code between start and end tags"
	[right]="all of template's code after endTag"
	*/    
    function SplitTemplate($startTag,$identifier,$endTag) {
		$identifiedStartsAt=strpos($this->TemplateContent,"$startTag$identifier");
		if ($identifiedStartsAt>0) {
			$identifiedEndsAt=strpos($this->TemplateContent,"$endTag",$identifiedStartsAt+strlen($startTag)+strLen($identifier));
			$_TemplateContentLeft=substr($this->TemplateContent,0,$identifiedStartsAt);
			$_TemplateContentRight=substr($this->TemplateContent,$identifiedEndsAt+strlen($endTag)+strlen($identifier));
			$_TemplateMiddle=substr($this->TemplateContent,0,$identifiedEndsAt);
			$_TemplateMiddle=substr($_TemplateMiddle,$identifiedStartsAt+strlen($identifier)+strlen($startTag));
			return array("left"=>$_TemplateContentLeft,"middle"=>$_TemplateMiddle,"right"=>$_TemplateContentRight);
		} else {
			return false;
		}
    }
    
	/*
	Method Prepare
	This method is mandatory to get the template processed. It takes the raw content and replaces the tokens with their values, 
	does iterations, hides/shows exclusive pairs.
	
	Example:
	$myInstance->Prepare();
	*/
    function Prepare($debug="") {
		$this->TemplateContent=$this->RawTemplate;
		
		if (count($this->Hiddens)!=0) {
			reset($this->Hiddens);
			while(list($what,$hidden)=each($this->Hiddens)) {
				$hidemeStartsAt=strpos($this->TemplateContent,"###$what");
				if ($hidemeStartsAt>0) {
					$hidemeEndsAt=strpos($this->TemplateContent,"###",$hidemeStartsAt+4);
					$_TemplateContentLeft=substr($this->TemplateContent,0,$hidemeStartsAt);
					$_TemplateContentRight=substr($this->TemplateContent,$hidemeEndsAt+3);
					$showMe=substr($this->TemplateContent,0,$hidemeEndsAt);
					$showMe=substr($showMe,$hidemeStartsAt+strlen($what)+3);
					if ($hidden) {
						$this->TemplateContent=$_TemplateContentLeft.$_TemplateContentRight;
					} else {
						$this->TemplateContent=$_TemplateContentLeft.$showMe.$_TemplateContentRight;
					}
				}
		
				$hidemeStartsAt=strpos($this->TemplateContent,"///$what");
				if ($hidemeStartsAt>0) {
					$hidemeEndsAt=strpos($this->TemplateContent,"///",$hidemeStartsAt+4);
					$_TemplateContentLeft=substr($this->TemplateContent,0,$hidemeStartsAt);
					$_TemplateContentRight=substr($this->TemplateContent,$hidemeEndsAt+3);
					$showMe=substr($this->TemplateContent,0,$hidemeEndsAt);
					$showMe=substr($showMe,$hidemeStartsAt+strlen($what)+3);
					if (!$hidden) {
						$this->TemplateContent=$_TemplateContentLeft.$_TemplateContentRight;
					} else {
						$this->TemplateContent=$_TemplateContentLeft.$showMe.$_TemplateContentRight;
					}
				}
			}
		}
		if (count($this->Sections)!=0) {
			reset($this->Sections);
			while(list($section,$enabled)=each($this->Sections)) {
				$records=$this->SectionTokens[$section];
				if (!is_array($records)) $records=array();
				$splited=$this->SplitTemplate("!!!***",$section,"***!!!");
				if ($splited) {
					$detailSection=$splited["middle"];
					$_TemplateContentLeft=$splited["left"];
					$_TemplateContentRight=$splited["right"];
					reset($records);
					$fullDetail="";
					for ($___x=0; $___x<count($records); $___x++) {
						$tokens=$records[$___x];
						reset($tokens);
						$_detail=$detailSection;
						while (list($token,$value)=each($tokens)) {
							$_detail=str_replace("%".$token."%",$value,$_detail);
						}
						$fullDetail.=$_detail;
					}
					if ($debug=="1") echo "<hr>$section: <br>".nl2br(htmlspecialchars($fullDetail))."<hr>";
					if ($enabled==1) 
						$this->TemplateContent=$_TemplateContentLeft.$fullDetail.$_TemplateContentRight;
					else
						$this->TemplateContent=$_TemplateContentLeft.$_TemplateContentRight;
				}
			}
		}
	
		reset($this->Tokens);
		while (list($token,$value)=each($this->Tokens)) {
			$this->TemplateContent=str_replace("%".$token."%",$value,$this->TemplateContent);
		}
    }

	/*
	Method Get:
	This method returns the processed template, without any browser output
	Example: 
	echo nl2br(htmlspecialchars($myInstance->Get()));
	*/
    function Get() {
		return $this->TemplateContent;
    }

	/*
	Method ShowIt:
	This method outputs the processed template to the browser.
	Example: 
	$myInstance->Showit();
	*/
    function ShowIt() {
		echo $this->TemplateContent;
    }
    
}

/*
Lets put all pieces together:

This is the file "test.php"
<?
$myIntance = new TemplateHandler("template");

$myInstance->SetToken("AUTHOR_NAME","Daniel Marjos");
$myInstance->SetToken("BORN","08/19/1970");
$myInstance->SetToken("HOBBIES","Read a lot, mess up with PHP");

$myInstance->SetDetailToken("PublishedClass",array(
	"CLASS_NAME"=>"clsSendMail",
	"PUBLISHED"=>"2003",
	"DESCRIPTION"=>"A simple class for sending mails"
));
$myInstance->SetDetailToken("PublishedClass",array(
	"CLASS_NAME"=>"classHTML",
	"PUBLISHED"=>"2003",
	"DESCRIPTION"=>"A simple class for creating HTML content"
));
$myInstance->SetDetailToken("PublishedClass",array(
	"CLASS_NAME"=>"clsCoffee",
	"PUBLISHED"=>"????",
	"DESCRIPTION"=>"A simple class for getting my breakfast from a web site"
));

$myInstance->Prepare();
$myInstance->Showit();

?>
------------------------------------------------------------------------------
This would be the file "templates/template.tpl"

<table>
	<tr>
		<td>Author name: %AUTHOR_NAME%<br>Born: %BORN%<br>Author's hobbies: %HOBBIES%<hr></td>
	</tr>
	<tr>
		<td>
			<table>
				<tr>
					<td>Class name</td>
					<td>Class published</td>
					<td>Description</td>
				</tr>
!!!***PublishedClass
				<tr>
					<td>%CLASS_NAME%</td>
					<td>%PUBLISHED%</td>
					<td>%DESCRIPTION%</td>
				</tr>
***!!!PublishedClass
			</table>
		</td>
	</tr>
</table>
-------------------------------------------------------------------------------

1) Please notice that !!!*** tag must be closed with ***!!!
2) No, there's no recursion in this version. 
3) If you relay on database results for SetDetailToken("your-section",array()), 
   remember to do a SectionStatus("your-section",false) before recordset processing.
   
Well... that's all, folks... I hope you enjoy this class
*/
?>
Return current item: TemplateHandler