Yii 1.1: ytheme

Template inheritance / nested views with no setup
6 followers

YTHEME

YTheme (YT) is a helper class based on Phpti (http://phpti.com) that fills the lack of template inheritance in Yii view files, it has:

  • Multi level template inheritance
  • Block definition with default content
  • Pure PHP with very low (almost zero) performance affect
  • Very simple, start using it in less than 30 minutes and with no setup

It is simple to learn, just jump to Phpti page (http://phpti.com) and read documentation. when you've learned that simple functions return here. I have classified simple functions of Phpti into a single helper named 'YT'. because we use YT many times it has to be short so I've created it as a helper. I've also converted Global vars to class static parameters.

Requirements

  • Yii (any ver.)

Usage

Please copy 'YT.php' to 'protected/helpers' directory of your application. Any function of Phpti is accessible via an static method of YT with same name:

<?php
YT::phptiFunctionName('phptiParam',...);
?>

Let's look at an example. We render our views as always, we pass parameters to views as always...

<?php
public function actionShow()
{
     $name = 'David';
     $city = 'Moscow';
     $this->render('details', array('name' => $name, 'city' => $city));
}
?>

In views, we can have any level of inheritance. let say we have a 'page' view file which has some Blocks (areas), named 'page.php':

<h1>Page</h1>
 
<div id="adv">
     <?php YT::emptyblock('advertise'); ?>
</div>
 
We are in <b><?php echo $city; ?></b><br/>
<?php YT::startblock('details'); ?>
So we have some DEFAULT content here, 
if none of other views override me then I'll be show. 
<?php YT::endblock(); ?>

Now we want to create a view file with different values for blocks we've defined in 'page.php', we call this view 'details.php':

<?php include YT::viewpath('page'); ?>
 
<?php YT::startblock('advertise'); ?>
Buy our products! they are good, I promise.
My name is <?php echo $name; ?>
<?php YT::endblock(); ?>
 
<?php YT::flushblocks(); ?>

You can see we just override contents of preferred blocks. this is the fact that is used in template frameworks like Twig. we have access to parameters passed by render() in any view (like '$city' in 'page.php').

You can continue inheritance in a new level, suppose we want a new view file that just appends some content to 'advertise' block of 'details.php'. we call that 'companyDetails.php':

<?php include YT::viewpath('details'); ?>
 
<?php 
YT::startblock('advertise');
YT::superblock(); 
?>
We have special plans for companies in <?php echo $city; ?>!
<?php 
YT::endblock(); 
 
YT::flushblocks();
?>

Beautiful huh? it's really powerful with simple code and OO style. Who needs a template framework?

Additional methods:

I've added some methods to Phpti, specified to Yii.

simpleblock:

It's useful when you want to work with very short values, it's self closed. for example:

<?php YT::simpleblock('pageTitle','Manage Orders'); ?>
 
//equals to:
<?php YT::startblock('pageTitle'); ?>
Manage Orders
<? php YT::endblock(); ?>

vars:

If you want to pass some values to layout files of Yii or upper level views in a quick way then var('key','value') is smiling. it's available globally in application:

YT::vars('userTypeString','Administrator'); //set value
echo YT::vars('userTypeString'); //get value

viewpath:

Yii is convenient when you want to find a view file, in the current theme or system views directory. We want to inherit from other files so we need a similar way in YT. Using raw include function of PHP we can refer to any relational path. To help with aliases I've added viewpath method that will search for views in both theme and system views, like Yii:

<?php
include YT::viewpath('master'); //in current dir
include YT::viewpath('products.master'); //in another controller/folder
include YT::viewpath('admin.products.master'); //in another module controller
include YT::viewpath('application.views.main', true); //absolute alias
?>

Filters:

Another ability of modern template frameworks is 'filters'. you can apply a filter on some content very fast and easy. I'm developing filters to work fine in Yii but currently you can define filter functions in another helper file and then use them:

<?php 
YT::startblock('advertise', 'strrev'); //apply strrev() PHP func
YT::startblock('advertise', 'myFunc'); //apply custom func
YT::startblock('advertise', 'strrev,myFunc'); //multiple filters
?>

Known problems:

You may found that 'YT::flushblocks()' reasonless. yes it is! Phpti has a collision with Yii internal ob_buffers and I can't find why till now. anyway, for now we have to call this method in the end of last view of inheritance, only last one. when we say 'last one' it means the view that we want to render.

In the above example if we want to render 'page' directly from controller then we have to add YT::flushblocks() in the end of that. if we do this, then children views will not render correctly. So we have to keep 'page.php' as is and create a new file with name like 'pageView.php' and then put the following content in that:

<?php 
include YT::viewpath('page'); 
YT::flushblocks(); 
?>

now we can render 'page' directly, also children views will render complete and good. If we want to render 'companyDetails.php' then we should remove 'YT::flushblocks()' from 'details.php', only one call of this method is enough for a inheritance series. Often we don't want to render parent views directly, but if we want the it's the way :) I'll try to fix it in new versions. If it's confusing then get your hands dirty and if still you have questions please use forum topic or this page's comments.

Resources

If you have any question please ask me in comments section, more info:

Total 2 comments

#5022 report it
RKK at 2011/09/07 06:46am
It's different

Yes CClipWidget is similar in fact that both capture content and share that globally. I've checked controller::beginClip() method when I was looking for something like what Twig delivers but it's not 'inheritance'. Phpti collects blocks of content in a stack, in the way that children are aware of ancestors, they can override blocks or inherit their content - also ancestors have their own default content...

it's a worth to have a look at Phpti for some minutes. in Yii even if Clips are enough for you, again Phpti's syntax and the way it works is very easier for a template design solution :)

#5021 report it
Say_Ten at 2011/09/07 05:22am
Advantages over CClipWidget?

The CClipWidget seems to cover this functionality also. As I'm not familiar with phpti, does it have advantages of the CClipWidget that I'm not aware of?

http://www.yiiframework.com/doc/api/1.1/CClipWidget/

Leave a comment

Please to leave your comment.

Create extension
Downloads