Welcome!

Join our community of MMO enthusiasts and game developers! By registering, you'll gain access to discussions on the latest developments in MMO server files and collaborate with like-minded individuals. Join us today and unlock the potential of MMO server development!

Join Today!

[PHP] Basic Templating System

Experienced Elementalist
Joined
Jul 23, 2012
Messages
201
Reaction score
128
Hello, in this tutorial i will show you how to create basic template system using PHP.

Last Update: 2013.02.12 / 2:00AM

So here is a list of what we need to do
  1. Create main class
  2. create basic functions that we will need
    1. Variables
      1. we will need static variable $globalVariables which will be an array
      2. we will need local variable $localVariables which will be an array
      3. we will need local variable $viewFile which will be a string
      4. we will need local variable $viewContent which will be a string
      5. we will need local variable $cacheEnabled which will be a bool (NEW)
    2. Functions
      1. we will need local function __construct
      2. we will need local function addLocalVariable
      3. we will need static function addGlobalVariable
      4. we will need local function formatArrayAs (NEW)
      5. we will need local function parseView
  3. Write code & Debug

Explanation for functions and variables

  1. Variables
    1. $globalVariables:this array will contain all global variables, global variables can be accessed from all view's.
    2. $localVariables: this array will contain all locally added variables for current view only.
    3. $viewFile: this string will contain view file name and latter full path of view file.
    4. $viewContent: this string will contain current template file source.
    5. $cacheEnabled: this will enabled or disable cache system for active view file
  2. Functions
    1. __construct: within this function you can set active template file (optional).
    2. addLocalVariable: this function will add new variable to local variable list.
    3. addGlobalVariable:this function will add new variable to global variable list.
    4. formatArrayAs: this function will parse array to an html formatted code.
    5. parseView: this function will parse and check all requirements for template file.
Hope this quick explanation will help you.

Lets start by creating class skeleton, witch should look something like this:
PHP:
class TemplateParser {

    /**
     * Contains all global scope variables that can be accessed from all template files.
     *
     * @var array
     */
    private static $globalVariables = array();
    /**
     * Contains current template specified variables, that can be accessed only from current template.
     *
     * @var array
     */
    private $localVariables = array();

    /**
     * Current view file location.
     *
     * @var null
     */
    private $viewFile = NULL;
    /**
     * Current view file content.
     *
     * @var string
     */
    private $viewContent = "";
    /**
     * Enable current view caching.
     *
     * @var bool
     */
    public $cacheEnabled = false;

    /**
     * Setting up default values for current template
     *
     * @param null $viewFile
     * @param bool $cacheEnabled
     */
    public function __construct($viewFile = NULL,$cacheEnabled = false)
    {
    }

    /**
     * Adds a local scope variable into array.
     *
     * @param $id
     * @param $value
     * @throws Exception
     */
    public function addLocalVariable($id,$value)
    {
    }

    /**
     * Adds a global scope variable into array.
     *
     * @param $id
     * @param $value
     * @throws Exception
     */
    public static function addGlobalVariable($id,$value)
    {
    }


    /**
     * Formats array items into html scripts, table or list.
     *
     * @param string $type
     * @param $data
     * @return string
     * @throws Exception
     */
    public function formatArrayAs($type = 'table',$data)
    {
    }

    /**
     * Parses a view file and outputs generated content.
     *
     * @param null $viewFile
     * @throws Exception
     */
    public function parseView($viewFile = NULL)
    {
    }
}

Next task is to figure out that problems we could encounter for each functions
  1. addLocalVariable,addGlobalVariable
    1. we should add a check if $id already exists in variable array's.
      1. How can we check that? simple, !
    2. we should add a check if $id is set and not empty.
      1. How can we check that? simple, !
    3. we should insert new variable into array.
      1. How can we do that? simple, !
  2. formatAsArray
    1. we should check if passed $data variable is an array.
      1. how can we do that? simple !
    2. we should check if array contains any items.
      1. How can we do that? simple, !
    3. we should add a check if $type exists in formating types array.
      1. How can we check that? simple, !
  3. parseView (Not updated)
    1. we should check if view file is set.
      1. How can we do that? simple, !
    2. we should add a check to check that view file exists
      1. How can we do that? simple, !
    3. we should read all template contents in to variable!
      1. How can we do that? simple, !
    4. we should merge local and global variable into one array
      1. How can we do that? simple, !
    5. we should add a check if that local or global variables array have any items in them
      1. How can we do that? simple, !
Lets create functions!
__construct
PHP:
    public function __construct($viewFile = NULL,$cacheEnabled = false)
    {
        $this->viewFile     = $viewFile;
        $this->cacheEnabled = $cacheEnabled;
    }
this simple function will set active template file, this parametr is optional since it has a default value, viewFile can be set from parseView function too.
addLocalVariable,addGlobalVariable
PHP:
    public function addLocalVariable($id,$value)
    {
        if(array_key_exists($id,$this->localVariables))
        {
            throw new Exception("Selected key '$id' already exist in array 'localVariables'");
        }

        if(!isset($id))
        {
            throw new Exception('Please recheck if $id value is set correctly!');
        }

        $this->localVariables[$id] = $value;
    }
    public static function addGlobalVariable($id,$value)
    {
        if(array_key_exists($id,self::$globalVariables))
        {
            throw new Exception("Selected key '$id' already exist in array 'self::globalVariables'");
        }

        if(!isset($id) OR !isset($id))
        {
            throw new Exception('Please recheck if $id,$value is set correctly!');
        }

        self::$globalVariables[$id] = $value;
    }
formatAsArray
PHP:
    public function formatArrayAs($type = 'table',$data)
    {
        if(!is_array($data))
        {
            throw new Exception('Wrong data type passed. $data only supports arrays! Your input data type:'.gettype($data));
        }

        $content = '';

        if(count($data) > 0)
        {
            $formatingTypes = array(
                'table' => array('<tr>','<td>','</tr>','</td>'),
                'list'  => array('','<li>','','</li>')
            );

            if(!array_key_exists($type,$formatingTypes))
            {
                throw new Exception('Unknown type provided. Your input:'.$type);
            }

            foreach($data as $string)
            {
                $content .= $formatingTypes[$type][1].$string.$formatingTypes[$type][3];
            }

            return $formatingTypes[$type][0].$content.$formatingTypes[$type][2];
        }
        return $content;
    }
parseView
PHP:
     public function parseView($viewFile = NULL)
    {
        if($this->viewFile == NULL)
        {
            if($viewFile == NULL)
            {
                throw new Exception('Template view file cannot be empty');
            }
            else
            {
                $this->viewFile = $viewFile;
            }
        }

        $this->viewFile = 'application/views/'.$this->viewFile.'.view';

        if(!is_file($this->viewFile))
        {
            throw new Exception('You must point to a valid view file!');
        }

        if($this->cacheEnabled == true AND is_file($this->viewFile.'.cache') AND time() - (10 * 60) < filemtime($this->viewFile.'.cache'))
        {
            $this->viewContent  = file_get_contents($this->viewFile.'.cache');
        }
        else
        {
            $this->viewContent  = file_get_contents($this->viewFile);
            $mergedVariables    = array_merge(self::$globalVariables,$this->localVariables);

            if(count($mergedVariables) > 0)
            {
                foreach($mergedVariables as $key => $value)
                {
                    $this->viewContent = str_replace("{".$key."}",$value,$this->viewContent);
                }
            }

            if($this->cacheEnabled == true)
            {
                file_put_contents($this->viewFile.'.cache',$this->viewContent);
            }
        }

        echo $this->viewContent;
    }

Full class:
PHP:
class TemplateParser {

    /**
     * Contains all global scope variables that can be accessed from all template files.
     *
     * @var array
     */
    private static $globalVariables = array();
    /**
     * Contains current template specified variables, that can be accessed only from current template.
     *
     * @var array
     */
    private $localVariables = array();

    /**
     * Current view file location.
     *
     * @var null
     */
    private $viewFile = NULL;
    /**
     * Current view file content.
     *
     * @var string
     */
    private $viewContent = "";
    /**
     * Enable current view caching.
     *
     * @var bool
     */
    public $cacheEnabled = false;

    /**
     * Setting up default values for current template
     *
     * @param null $viewFile
     * @param bool $cacheEnabled
     */
    public function __construct($viewFile = NULL,$cacheEnabled = false)
    {
        $this->viewFile     = $viewFile;
        $this->cacheEnabled = $cacheEnabled;
    }

    /**
     * Adds a local scope variable into array.
     *
     * @param $id
     * @param $value
     * @throws Exception
     */
    public function addLocalVariable($id,$value)
    {
        if(array_key_exists($id,$this->localVariables))
        {
            throw new Exception("Selected key '$id' already exist in array 'localVariables'");
        }

        if(!isset($id))
        {
            throw new Exception('Please recheck if $id,$value is set correctly!');
        }


        $this->localVariables[$id] = $value;
    }

    /**
     * Adds a global scope variable into array.
     *
     * @param $id
     * @param $value
     * @throws Exception
     */
    public static function addGlobalVariable($id,$value)
    {
        if(array_key_exists($id,self::$globalVariables))
        {
            throw new Exception("Selected key '$id' already exist in array 'self::globalVariables'");
        }

        if(!isset($id) OR !isset($id))
        {
            throw new Exception('Please recheck if $id,$value is set correctly!');
        }

        self::$globalVariables[$id] = $value;
    }


    /**
     * Formats array items into html scripts, table or list.
     *
     * @param string $type
     * @param $data
     * @return string
     * @throws Exception
     */
    public function formatArrayAs($type = 'table',$data)
    {
        if(!is_array($data))
        {
            throw new Exception('Wrong data type passed. $data only supports arrays! Your input data type:'.gettype($data));
        }

        $content = '';

        if(count($data) > 0)
        {
            $formatingTypes = array(
                'table' => array('<tr>','<td>','</tr>','</td>'),
                'list'  => array('','<li>','','</li>')
            );

            if(!array_key_exists($type,$formatingTypes))
            {
                throw new Exception('Unknown type provided. Your input:'.$type);
            }

            foreach($data as $string)
            {
                $content .= $formatingTypes[$type][1].$string.$formatingTypes[$type][3];
            }

            return $formatingTypes[$type][0].$content.$formatingTypes[$type][2];
        }
        return $content;
    }

    /**
     * Parses a view file and outputs generated content.
     *
     * @param null $viewFile
     * @throws Exception
     */
    public function parseView($viewFile = NULL)
    {
        if($this->viewFile == NULL)
        {
            if($viewFile == NULL)
            {
                throw new Exception('Template view file cannot be empty');
            }
            else
            {
                $this->viewFile = $viewFile;
            }
        }

        $this->viewFile = 'application/views/'.$this->viewFile.'.view';

        if(!is_file($this->viewFile))
        {
            throw new Exception('You must point to a valid view file!');
        }

        if($this->cacheEnabled == true AND is_file($this->viewFile.'.cache') AND time() - (10 * 60) < filemtime($this->viewFile.'.cache'))
        {
            $this->viewContent  = file_get_contents($this->viewFile.'.cache');
        }
        else
        {
            $this->viewContent  = file_get_contents($this->viewFile);
            $mergedVariables    = array_merge(self::$globalVariables,$this->localVariables);

            if(count($mergedVariables) > 0)
            {
                foreach($mergedVariables as $key => $value)
                {
                    $this->viewContent = str_replace("{".$key."}",$value,$this->viewContent);
                }
            }

            if($this->cacheEnabled == true)
            {
                file_put_contents($this->viewFile.'.cache',$this->viewContent);
            }
        }

        echo $this->viewContent;
    }
}


Sorry didnt have time to finish this tut, but i will finish this asap... :D
 
Last edited:
Experienced Elementalist
Joined
Jul 23, 2012
Messages
201
Reaction score
128
Usage Example:

home.view

PHP:
<b>This page title is: {title}</b>
<table>
    <tr>
        <td >looool</td>
        <td >looool</td>
    </tr>
    {my_array}
</table>
index.php
PHP:
include 'system/class/TemplateParser.php';


$t = new TemplateParser();

$t->cacheEnabled = true;

TemplateParser::addGlobalVariable('title','lol;');

$t->addLocalVariable('my_array',$t->formatArrayAs('table',array('lol','lil')));


$t->parseView('home');

home.view.cache
PHP:
<b>This page title is: lol;</b>
<table>
    <tr>
        <td >looool</td>
        <td >looool</td>
    </tr>
    <tr><td>lol</td><td>lil</td></tr>
</table>
 
Newbie Spellweaver
Joined
Jun 10, 2013
Messages
94
Reaction score
21
Nice tutorial but I still prefer using SMARTY.
 
Newbie Spellweaver
Joined
Jun 10, 2013
Messages
94
Reaction score
21
Smarty, you should really use RainTPL, better than smarty, faster than smarty, easier than smarty.

Since almost 0% times I work with no php framework I dont really use templating systems, but I will give RainTPL a look hehe.
 
Newbie Spellweaver
Joined
Jun 10, 2013
Messages
94
Reaction score
21
I do. But a far future project includes making a CMS for Perfect World section , which would also have a templating system. In fact I want to make it cross gaming compatible , but that will be seen if it can be done at all.

Then use laravel framework
 
Experienced Elementalist
Joined
Jul 23, 2012
Messages
201
Reaction score
128
If anyone needs here is newer version with html compacter and basic loop support
PHP:
<?php
/**
 * CodeCMS
 *
 * Author : Kristians Jaunzems
 * Date   : 13.11.7/12:11
 *
 */

class TemplateParser {

    /**
     * Contains all global scope variables that can be accessed from all template files.
     *
     * @var array
     */
    private static $globalVariables = array();
    /**
     * Contains current template specified variables, that can be accessed only from current template.
     *
     * @var array
     */
    private $localVariables = array();

    /**
     * Contains all variables in one array
     *
     * @var array
     */
    private $mergedVariables = array();

    /**
     * Holds all language related variables
     *
     * @var array
     */
    private $languageVariables = array();

    /**
     * Current view file location.
     *
     * @var null
     */
    private $viewFile = NULL;
    /**
     * Current view file content.
     *
     * @var string
     */
    private $viewContent = "";
    /**
     * Enable current view caching.
     *
     * @var bool
     */
    public $cacheEnabled = false;

    /**
     * Enable removing all whitespaces and tabs
     *
     * @var bool
     */
    public $compact = true;

    /**
     * Setting up default values for current template
     *
     * @param null $viewFile
     * @param bool $cacheEnabled
     */
    public function __construct($viewFile = NULL,$cacheEnabled = false)
    {
        $this->viewFile     = $viewFile;
        $this->cacheEnabled = $cacheEnabled;
    }

    /**
     * Adds a local scope variable into array.
     *
     * @param $id
     * @param $value
     * @throws Exception
     */
    public function addLocalVariable($id,$value)
    {
        if(array_key_exists($id,$this->localVariables))
        {
            throw new Exception("Selected key '$id' already exist in array 'localVariables'");
        }

        if(!isset($id))
        {
            throw new Exception('Please recheck if $id,$value is set correctly!');
        }

        $this->localVariables[$id] = $value;
    }

    /**
     * Adds a global scope variable into array.
     *
     * @param $id
     * @param $value
     * @throws Exception
     */
    public static function addGlobalVariable($id,$value)
    {
        if(array_key_exists($id,self::$globalVariables))
        {
            throw new Exception("Selected key '$id' already exist in array 'self::globalVariables'");
        }

        if(!isset($id))
        {
            throw new Exception('Please recheck if $id,$value is set correctly!');
        }

        self::$globalVariables[$id] = $value;
    }

    /**
     * Loads language file variables into language variable
     *
     * @param string $file
     * @param string $locale
     * @throws Exception
     */
    public function prepareLanguage($file = 'global',$locale = config::locale)
    {
        if(!is_file("application/languages/$locale/$file.php"))
        {
            throw new Exception('Template language file not found! Locale:'.$locale.' File:'.$file);
        }

        $language = array();

        include "application/languages/$locale/$file.php";

        $this->languageVariables =  $language;

        $language = NULL;
    }


    /**
     * Formats array items into html scripts, table or list.
     *
     * @param string $type
     * @param $data
     * @return string
     * @throws Exception
     */
    public function formatArrayAs($type = 'table',$data)
    {
        if(!is_array($data))
        {
            throw new Exception('Wrong data type passed. $data only supports arrays! Your input data type:'.gettype($data));
        }

        $content = '';

        if(count($data) > 0)
        {
            $formatingTypes = array(
                'table' => array('<tr>','<td>','</tr>','</td>'),
                'list'  => array('','<li>','','</li>')
            );

            if(!array_key_exists($type,$formatingTypes))
            {
                throw new Exception('Unknown type provided. Your input:'.$type);
            }

            foreach($data as $string)
            {
                $content .= $formatingTypes[$type][1].$string.$formatingTypes[$type][3];
            }

            return $formatingTypes[$type][0].$content.$formatingTypes[$type][2];
        }
        return $content;
    }

    /**
     * Parses a view file and outputs generated content.
     *
     * @param null $viewFile
     * @throws Exception
     */
    public function parseView($viewFile = NULL)
    {
        if($this->viewFile == NULL)
        {
            if($viewFile == NULL)
            {
                throw new Exception('Template view file cannot be empty');
            }
            else
            {
                $this->viewFile = $viewFile;
            }
        }

        $cacheFile      = 'application/views/cache/'.$this->viewFile.'.html';
        $this->viewFile = 'application/views/'.$this->viewFile.'.view';

        if(!is_file($this->viewFile))
        {
            throw new Exception('You must point to a valid view file!');
        }

        if($this->cacheEnabled == true AND is_file($cacheFile) AND time() - (10 * 60) < filemtime($cacheFile))
        {
            $this->viewContent  = file_get_contents($cacheFile);
        }
        else
        {
            $this->viewContent      = file_get_contents($this->viewFile);
            $this->mergedVariables  = array_merge(self::$globalVariables,$this->localVariables,$this->languageVariables);

            if(preg_match_all("/{{([^\/}]+)}}(.*){{\/\\1}}/ms", $this->viewContent, $matches) !== false)
            {
                $loopStrings    = $matches[0];
                $loopVariables  = $matches[1];
                $loopBlocks     = $matches[2];

                for($i = 0; $i < count($loopVariables); $i++)
                {
                    if(isset($this->mergedVariables[$loopVariables[$i]]) && is_array($this->mergedVariables[$loopVariables[$i]]))
                    {
                        $preparedString = "";

                        for($j = 0; $j < count($this->mergedVariables[$loopVariables[$i]]); $j++)
                        {
                            $block = $loopBlocks[$i];
                            foreach($this->mergedVariables[$loopVariables[$i]][$j] as $key => $value)
                            {
                                $block = str_replace("{{" . $key . "}}", $value, $block);
                            }
                            $preparedString .= $block;
                        }
                        $this->viewContent = str_replace($loopStrings[$i], $preparedString, $this->viewContent);
                    }
                    else
                    {
                        $this->viewContent = str_replace($loopStrings[$i], "", $this->viewContent);
                    }
                }
            }

            $this->viewContent = preg_replace("/{{[^}]+}}/", "", $this->viewContent);

            if(count($this->mergedVariables) > 0)
            {
                foreach($this->mergedVariables as $key => $value)
                {
                    if(!is_array($value))
                    {
                        $this->viewContent = str_replace("{".$key."}",$value,$this->viewContent);
                    }
                }
            }

            if($this->compact == true)
            {
                $this->viewContent = preg_replace("/\n|\t|\r/", " ", $this->viewContent);
                $this->viewContent = preg_replace("/ +/", " ", $this->viewContent);
            }

            if($this->cacheEnabled == true)
            {
                if(!is_dir('application/views/cache/'))
                {
                    mkdir('application/views/cache/');
                }
                file_put_contents($cacheFile,$this->viewContent);
            }
        }

        echo $this->viewContent;
    }

    /**
     * Cleans variable data to null
     *
     * @param bool $cleanGlobal
     */
    public function clean($cleanGlobal = false)
    {
        $this->languageVariables    = NULL;
        $this->localVariables       = NULL;
        $this->mergedVariables      = NULL;
        $this->viewContent          = NULL;

        if($cleanGlobal == true)
            self::$globalVariables = NULL;
    }
}

PHP:
data = array(      0 =>     array(         'mylol1'   => 'tests1',         'mylol2' => 'tests2'     ),     1 =>     array(     'mylol1'   => 'tests3',     'mylol2' => 'tests4'),      2 =>     array(     'mylol1'   => 'tests5',     'mylol2' => 'tests6'     ) ); $t->addLocalVariable('my_array',$data);

Code:
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd"> <html> <body> <b>This page title is: {tsitle}</b> <table>          <tr>         {{my_array}}             <td >{{mylol1}}</td>             <td >{{mylol2}}</td>         {{/my_array}}         </tr>  </table> </body> </html>
 
Back
Top