Templates!!!

Coding Critique is the place to post source code for peer review by other members of DevNetwork. Any kind of code can be posted. Code posted does not have to be limited to PHP. All members are invited to contribute constructive criticism with the goal of improving the code. Posted code should include some background information about it and what areas you specifically would like help with.

Popular code excerpts may be moved to "Code Snippets" by the moderators.

Moderator: General Moderators

Post Reply
User avatar
jackpf
DevNet Resident
Posts: 2119
Joined: Sun Feb 15, 2009 7:22 pm
Location: Ipswich, UK

Templates!!!

Post by jackpf »

Ok...I've been thinking long and hard about this...

Before now, I've always echo'd HTML and stuff from within my PHP scripts. This was ok, because my site has been pretty small..but it's getting a bit bigger now, and I think it'd be easier to maintain with templates.

Anyway, I've been thinking about how to construct and parse template files. The idea is to keep logic in the scripts, and display stuff in the templates. I came to realise that PHP can in fact do both of these very well, without having to create a new language for templates.

So anyway, this is the templating system I've come up with. This is the main class:

Code: Select all

class template
{
    private static $vars = array();
    
    public static function assign_vars(array $vars)
    {
        self::$vars = array_merge(self::$vars, $vars);
    }
    private static function assign_global_vars()
    {
        $stdClass = new stdClass;
        
        foreach($GLOBALS as $key => $value)
        {
            $stdClass->$key = $value;
        }
        
        return $stdClass;
    }
    public static function compile($template, $function)
    {
        global $config_init;
        
        //flush current output buffer
        ob_end_flush();
        //start output buffering to catch template
        ob_start();
        
        //execute template
        $file = $_SERVER['DOCUMENT_ROOT'].'/templates/'.$template.'.template.php';
        
        if(file_exists($file))
        {
            include $file;
            
            if(function_exists($function) && is_callable($function))
            {
                echo $function((object) self::$vars, self::assign_global_vars());
            }
            else
            {
                trigger_error('Template function '.$function.' is non-existent!', E_USER_ERROR);
            }
        }
        else
        {
            trigger_error('Template file '.$file.' is non-existent!', E_USER_ERROR);
        }
        
        //get template contents
        $ob = ob_get_contents();
        
        //end output buffering
        ob_end_clean();
        
        //restart output buffering
        ob_start(((bool) $config_init->get_config('compress_output_buffer')) ? 'ob_gzhandler' : null);
        
        //return contents
        return $ob;
    }
}
Here's an example of how it would be used:
The script:

Code: Select all

include 'template_class.php';
 
$some_var = 'hello world';
 
template::assign_vars(array(
'hello' => $some_var
));
 
echo template::compile('template_file', 'template_function');
And template_file.template.php

Code: Select all

<?function template_function($vars, $globals){?><html><body><h1><?=$vars->hello?></h1></body></html><?}?>
Anyway, I was just hoping to get some feedback. Anything that could be improved? Anything that you would do differently? I'm not sure if I should have static methods (like I do currently) so that child templates can inherit variables from parent templates...thoughts? :)

Also, I currently have to use output buffering to catch the template (since I close PHP tags)...is there a better way of doing this?

Yeah, and is it OK to supply the template with all defined variables? I only do this so that I don't have to repeatedly assign variables that are used often...for example, if I have a variable $file_path which is used in every link, simply using that from the $globals object would be a lot simpler than assigning it to every template, don't you think?

Anyway, yeah, all opinions appreciated :)
Thanks,
Jack.
User avatar
Christopher
Site Administrator
Posts: 13596
Joined: Wed Aug 25, 2004 7:54 pm
Location: New York, NY, US

Re: Templates!!!

Post by Christopher »

Why static? What if you want to use multiple templates, each with it own vars assigned, on the same page?
(#10850)
User avatar
jackpf
DevNet Resident
Posts: 2119
Joined: Sun Feb 15, 2009 7:22 pm
Location: Ipswich, UK

Re: Templates!!!

Post by jackpf »

That's what I was thinking about...I will need to use multiple templates for the same page.

But, if I leave it static, then all templates can inherit variables that are used a lot. That would save me having to assign the same variables to each template...I could just assign the variable to the main template, then all the templates would have access to it.

But yeah, I might not have them static...I'm not sure.
MichaelR
Forum Contributor
Posts: 148
Joined: Sat Jan 03, 2009 3:27 pm

Re: Templates!!!

Post by MichaelR »

jackpf wrote:But, if I leave it static, then all templates can inherit variables that are used a lot. That would save me having to assign the same variables to each template...I could just assign the variable to the main template, then all the templates would have access to it.

But yeah, I might not have them static...I'm not sure.
I'm new to objects in PHP, but can't you use interfaces for this effect? Or abstract classes? I can't remember which.
User avatar
Christopher
Site Administrator
Posts: 13596
Joined: Wed Aug 25, 2004 7:54 pm
Location: New York, NY, US

Re: Templates!!!

Post by Christopher »

jackpf wrote:But, if I leave it static, then all templates can inherit variables that are used a lot. That would save me having to assign the same variables to each template...I could just assign the variable to the main template, then all the templates would have access to it.
Do you have a lot of variables that are used by all templates?
(#10850)
User avatar
jackpf
DevNet Resident
Posts: 2119
Joined: Sun Feb 15, 2009 7:22 pm
Location: Ipswich, UK

Re: Templates!!!

Post by jackpf »

Not particularly...but this is still in the design stages...

Anyway, I've changed it to a dynamic class now...

But I am having difficulty with displaying errors. Currently, in order to display an error, I have to return the current template to the parent file. This is inconvenient, but works. However, when other functions need to display errors, how do I display them without messing up the template?

I can't figure it out...
joeynovak
Forum Commoner
Posts: 26
Joined: Sun May 10, 2009 11:09 am

Re: Templates!!!

Post by joeynovak »

That's really cool! Templates definitely make a large site easier to maintain. It's an application of the "DRY" rule, or "Don't Repeat Yourself" that is so so critical to maintainable software.

If you seperate your code into MVC, it is really easy to just use regular php files as templates. Just set a variable, and then use "include" to show a "template" (which is just another php file), the php file you include has access to all the variables that are available when you call the "include".

So a "template" and it's caller would look like:

Code: Select all

 
<?php
hello_world();
function hello_world(){
  $title = "Title";
  $body = "Hellow World!";
  include('template.php');
}
?>
 
(template.php)

Code: Select all

 
<html>
<head>
<title><?php echo $title; ?></title>
</head>
<body><?php echo $body; ?></body>
</html>
 
In my code (I do Java Full Time as my day job), I put all the variables I want accessible by my "view" in a global array. So, I would put title in $_GLOBAL['params']['title']. (This is similar to request.setAttribute(String, String) in Java).

Regardless, your code is really cool. Huge Props!

Joey
User avatar
jackpf
DevNet Resident
Posts: 2119
Joined: Sun Feb 15, 2009 7:22 pm
Location: Ipswich, UK

Re: Templates!!!

Post by jackpf »

Hey, thanks :)

Yeah...I think our ideas are pretty similar, except I try not to use the global scope...since that would tempt me to just process stuff in the template rather than in the script, where it should be. By using only assigned variables, you limit the amount of processing in the template to only what you need. It also lets you easily keep track of what variables are in use in the template etc...

But yeah, cheers :)

I'm still having a bit of trouble with displaying errors...how do you do it, may I ask? Do you have a specific template for errors, and load them when your script encounters an error, or redirect them to a new page...? I'm sure I'll figure it out eventually...

All the best,
Jack.
revention
Forum Newbie
Posts: 3
Joined: Sun Aug 16, 2009 1:01 pm

Re: Templates!!!

Post by revention »

Looks OK to me....but wouldn't a global variable fix one or two of the problems...?
User avatar
jackpf
DevNet Resident
Posts: 2119
Joined: Sun Feb 15, 2009 7:22 pm
Location: Ipswich, UK

Re: Templates!!!

Post by jackpf »

Yeah...but I try to use globals as seldom as possible. That way I can keep a track on what variables are being used where.

But yeah...I've pretty much rewritten the thing now anyway :)

Instead of posting the whole thing here again.... http://jackpf.co.uk/blog/184

My entire blog is running using that templating system now :)

Now I have the rest of the site to do.... *sigh*.

Nah, I'll do it over a long period of time. Maybe a couple of sections a day. Shouldn't get too boring :D
joeynovak
Forum Commoner
Posts: 26
Joined: Sun May 10, 2009 11:09 am

Re: Templates!!!

Post by joeynovak »

Hey Jackpf,

Thanks!

Errors... Good question... I just write awesome code to begin with that doesn't have errors... ;) (j/k)

You know, I usually tend to just ignore them... (shhhh... don't tell anyone :) ) (I'm sure people are going to say "That's bad") Occasionally I'll write something to handle a specific error, but once you are done debugging your code, and you have a system of some kind in place that you use repeatedly the number of php errors you get in finished code goes down significantly. I use an ORM, so there are never sql errors unless the db isn't up to date.

For validation errors, I usually just create a list of errors, and display them all somehow when done (a quick template that takes an array or errors, and displays them). At the same time, I try to really really limit data validation. I mean, the easier you make your site / form to use, the more people enjoy it. So, I require as few fields as possible, and make it as flexible as I can. So, I write very little error handling code (unless it's financial in nature, then I handle the important errors).

Joey
User avatar
jackpf
DevNet Resident
Posts: 2119
Joined: Sun Feb 15, 2009 7:22 pm
Location: Ipswich, UK

Re: Templates!!!

Post by jackpf »

Ahh right. I didn't mean like...coding errors ;) I meant like...user errors. Like...they've submitted invalid data or whatever.

But yeah...I think that's what I'm going to do as well...have a specific template to handle errors...

Currently I use the trigger_error() function along with set_error_handler() to handle my custom errors...so it'll be pretty easy to change that to just load up the error template and stop parsing the script.

Thanks for the ideas :)
Post Reply