Welcome Guest, Not a member yet? Register   Sign In
New library for doing "template inheritance" *without* a template parser
#1

[eluser]arshaw[/eluser]
Hello all! I've always found django's template inheritance to be invaluable when organizing my template code. I've always wanted the same in PHP, but without a cumbersome template parser like smarty. I've just developed a library to do this in pure PHP:

PHP Template Inheritance

Internally, it uses output buffers, but its API is very simple and easy to use. For example, here is a "parent" template:

Code:
<html>
<body>
<h1>
&lt;? startblock('title') ?&gt;
&lt;? endblock() ?&gt;
</h1>
<div id='article'>
&lt;? startblock('article') ?&gt;
&lt;? endblock() ?&gt;
</div>
&lt;/body&gt;

and here is the "child" template:

Code:
&lt;? include 'parent.php' ?&gt;

&lt;? startblock('title') ?&gt;
   This is the title
&lt;? endblock() ?&gt;

&lt;? startblock('article') ?&gt;
   This is the article
&lt;? endblock() ?&gt;

and here is what it outputs:

Code:
&lt;html&gt;
&lt;body&gt;
<h1>
   This is the title
</h1>
<div id='article'>
   This is the article
</div>
&lt;/body&gt;
&lt;/html&gt;

I really think this would be useful in CodeIgniter, which I praise for its lack of template engine (by default), and going the straight PHP route for view code. I'd love to hear what you guys think, and whether you think it'd be appropriate to include this in a codeigniter distro.
#2

[eluser]jonldavis[/eluser]
Arshaw, This sounds like something I could use. I've got something like this:

(default.php)
Code:
&lt;?php require_once '../lib/phpti/ti.php' ?&gt;
&lt;?php startblock('header') ?&gt;
&lt;?php endblock() ?&gt;
&lt;body&gt;
&lt;?php startblock('top-bar') ?&gt;
&lt;?php endblock() ?&gt;
&lt;?php startblock('menu') ?&gt;
&lt;?php endblock() ?&gt;
    <div id="main">
      <h1>Hello, world!</h1>
    </div> &lt;!-- main --&gt;
&lt;?php startblock('footer') ?&gt;
&lt;?php endblock() ?&gt;
&lt;/body&gt;
&lt;/html&gt;
(blocks.php)
Code:
&lt;?php include 'default.php' ?&gt;

&lt;?php startblock('header')?&gt;
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
&lt;html&gt;
&lt;head&gt;
    &lt;meta http-equiv="Content-Type" content="text/html; charset=UTF-8"&gt;
    &lt;title&gt;&lt;?php echo $site_name; ?&gt;&lt;/title&gt;
&lt;/head&gt;
&lt;?php endblock() ?&gt;

&lt;?php startblock('top-bar') ?&gt;
<p>Page header stuff here</p>
&lt;?php endblock() ?&gt;

&lt;?php startblock('menu')?&gt;
<p>menu list here</p>
&lt;?php endblock() ?&gt;

&lt;?php startblock('footer') ?&gt;
<p>page footer here</p>
&lt;?php endblock() ?&gt;

I've got blocks.php in the same directory as default.php (apps/codeigniter/views). In my controller I'm trying to display it using
Code:
$this->load->view('default', $page_data);
. What I get is just the "Hello, world!" in default.php -- the child blocks are not found. It seems that the system does not know where to find the blocks file. I've tried various means of specifying a path on the include in blocks.php, but without success.

Probably some thing small I missed in the docs...
#3

[eluser]arshaw[/eluser]
hello jonldavis. when you load the view, you actually need to load the child template. so do:

Code:
$this->load->view('blocks', $page_data);

a problem you might encounter is that blocks.php might not find default.php. i'm not sure the best technique for doing this in codeigniter, but you might try a relative include like

Code:
&lt;?php include dirname(__FILE__) . '/default.php' ?&gt;
#4

[eluser]Seyed Mohsen Ahmadzadeh[/eluser]
Hi friends.
I've got two questions.
1- Can we use joomla's template in CI?
2- Could you upload example file here?
Thanks a lot.
#5

[eluser]Seyed Mohsen Ahmadzadeh[/eluser]
Hi friends.
Why don't answer my questions?
are they so difficult?
#6

[eluser]arshaw[/eluser]
1- i don't know what joomla's template system has to do with this post. this post is about phpti (phpti.com). i cant answer this question

2- examples are located at phpti.com
#7

[eluser]ThijssjihT[/eluser]
I did it like this:

only 1 view: templateview.php
In this I only do layout. All links are variable. Example:
Code:
&lt;html&gt;
&lt;head&gt;
&lt;title&gt;&lt;?=$pagetitle?&gt;&lt;/title&gt;
&lt;?php foreach ($metatags as $tag):
echo $tag;
endforeach; ?&gt;
&lt;/head&gt;
&lt;body&gt;
<h1>&lt;?=$head1?&gt;</h1>
<p>&lt;?=$content1?&gt;</p>
<h1>&lt;?=$head2?&gt;</h1>
<p>&lt;?=$content2?&gt;</p>
&lt;/body&gt;
&lt;/html&gt;

For each page, make a controller. Home.php Blog.php Guestbook.php... There is no controller named template.php, I use a model.
Code:
function index()
{
$this->load->model('Template');

$data = $this->Template->ltc();

// Store all page specific data in a $data array

$this->load->view('template');
}

Then make a model template.php, where you initialize all data that should be used in all pages, like metatags, title, navigation bar, text for in your logo. This can be variable, so you can load it with a function. This is my template.php:
Code:
&lt;?php
class Template extends Model {
    
    function Template()
    {
        parent::Model();
    }
    
    function ltc()
    {    
        $array = $this->current_page();
        
        $data['include'] = base_url() . 'include';
        $data['pagetitle'] = $array['pagetitle'];
        $data['page'] = $array['page'];
        
        $data['more'] = 'Meer...';        
        $data['newshead'] = 'Nieuws:';
        
        $data['newsdate1'] = '***';
        $data['newshead1'] = 'To be replaced';
        $data['news1'] = '';
        $data['newslink1'] = '#';
        
        $data['newsdate2'] = '';
        $data['newshead2'] = '';
        $data['news2'] = '';
        $data['newslink2'] = '#';
        
        return $data;
    }
    
    function current_page()
    {
        $page = $this->uri->segment(1);
        
        switch ($page){
            case FALSE:
            case "home":
                return array('page' => 'Home', 'pagetitle' => 'Thijs-Janssen.nl');
                break;
            case "blog":
                return array('page' => 'Blog', 'pagetitle' => 'Thijs’ Weblog &nbsp;&nbsp;&nbsp; Thijs-Janssen.nl');
                break;
            case "links":
                return array('page' => 'Links', 'pagetitle' => 'Links &nbsp;&nbsp;&nbsp; Thijs-Janssen.nl');
                break;
            default:
                return array('page' => '*UNKNOWN PAGE*', 'pagetitle' => '*ERROR: UNKNOWN PAGE* &nbsp;&nbsp;&nbsp; Thijs-Janssen.nl');
                break;
        }
    }
}
?&gt;
I'll try to explain the difference between variable data you put in your controllers and variable data you put in you template.php.
The 'page' key from the array in the current_page() function is used to display the name of the page in my logo. The 'pagetitle' is displayed in the &lt;title&gt;-tag. However it differs with the page you're viewing, on a page it is constant. When I add some content, or delete some content, this data won't change. You can separate data you are likely to change and data you aren't likely to change like this.

There is a huge drawback for this method, but I found a solution for that. Let me first explain the problem here.

Every page looks the same. Of course this is what you are trying to accomplish with an template, but if you need 3 headings and 3 pieces of content on the first page, and only 2 on the second page, you'll get a php error for the $head3 and $content3 variable, because they doesn't exist, but they are needed in your view. You can't send empty strings, '&nbsp;' as $head3 and $content3, because empty variables aren't passed to the view, even if they are in the array, and '&nbsp;' might screw up your layout.

There are 2 solutions for this, depending on the situation:

1.
instead of putting this in your controller:
Code:
$data['head1'] = 'this is the first heading';
$data['content1'] = 'example content';
$data['head2'] = 'second heading';
$data['content2'] = 'even more content';
do this:
Code:
$data['head'] = array('this is the first heading', 'second heading');
$data['content'] = array('example content', 'even more content');
and use a while loop in your view like this:
Code:
&lt;?php
while ($item = current($head)){
echo '<h1>' . $item . '</h1>';
echo '<p>' . $content[key($item)] . '</p>';
next($head);
}
This method is the easiest and shortest solution, but you won't be able to use different styles on these sections. If you want to display or hide sections with specific styles, instead use methode 2:


2.
give every section an extra variable $data['display'], which can be 'style="display: none"' or ''. For each section do this in your view:
Code:
<div &lt;?=$display?&gt;>
so it can be set hidden or showed in the controller.
This method requires more interference with the view, so your code will be a little messier. Also your template will be a lot bigger. You do have a lot more options with your template with this method though.

So we have a controller, calling a template model to load page constants and returns it as an array. Then the controller stores all other data in the same array. Then it calls a template view.
For different pages, you need different controllers, but you only need one model and one view, so no html code will be duplicated.

You'll have a template, without a template parser, with nice clean code. It's easy to forget to store some variables in the array though, so watch out for that. If you do forget, you'll get a php error, but other code is displayed, so it's easy to find what causes you're error.

It took me 1,5 hour to post this message, with only 49 characters remaining for this message. I might explain it a little better if you have questions another day. Good luck, and sorry for my bad english. There might be some typo's or missing semicolons in the code too, so don't copy/paste it.
#8

[eluser]Unknown[/eluser]
$this->benchmark->elapsed_time() or {elapsed_time}
$this->benchmark->memory_usage() or {memory_usage}

these aren't work on phpti template
I found Loader.php@856
ob_get_leve() too high


edit::
i add flushblocks() @ end of view and file it's work.




Theme © iAndrew 2016 - Forum software by © MyBB