Wednesday, April 18th, 2007
Template View and View Helper Design Patterns in PHP (updated v2)
The Template View and View Helper patterns lend themselves nicely when it comes to developing a View Layer solution for PHP, or so I found out with the recent refactoring of Cubix (dubbed Cubix II). This View layer duo is very much a great candidate for a “tag team”. Each component performs a role and together make up a big part of the View Layer.
update: Now includes View Helper Locator example.
The Template View Design Pattern
First let’s examine the Template View. What is a template view exactly?
Well if you have started programming PHP you’ve basically been using the Template View pattern all along
Code like the following excerpt is a Template View.
Simple Template View
<html>
<head><title><?php echo $title; ?></title></head>
<body>
<?php echo $heading; ?>
<?php echo $content; ?>
</body>
</html>
But of course, in the beginning, when we learn to program beyond <?php echo ‘hello world - this is my very first php script’; ?> examples, we learn about if statements, database access and for/foreach, while/do while loops, tools and great “super powers” that liberate us from static pages, dreamweaver templates and other statically managed content.
Pretty soon, you’ve experimented with php to the point that you’re now able to connect to a database and display dynamic content on your page.
Now your Template View looks like spaghetti.
Spaghetti Code
$db = mysql_connect(‘localhost’,‘root’,’somepass’);
$selectDb = mysql_select_db(’someDB’, $db);
$sql = "SELECT *
FROM `some_table`
WHERE fromdate < NOW()";
$result = mysql_query($sql, $db); ?>
<html>
<head>
<title>
<?php echo $title; ?>
</title></head>
<body>
<?php
if ($result) {
while ($row = mysql_fetch_assoc($result)) {
echo ‘<h2>’.$row[‘heading’] . ‘</h2>’;
echo ‘<p>’.$row[’summary’].‘</p>’;
}
}
<hr />
<?php / some other crap here;?>
</body>
</html>
That was just an example as to how you may have used the Template View in the first place and was my best effort at writing crappy code. Anyway, back into it.
The main difference between Your first procedural scripts (or Server Pages as Fowler refers to them in his book PoEAA - as his background is main Java/Smalltalk ie JSP) and a Template View is that the Template View:
- Is a lot cleaner - It does not contain presentation logic. No loops, No if statements. No decision making. It’s a template and will only be utilising simple display functions such as echo or perhaps include()/require().
- It doesn’t get called directly - obviously it’s part of the View layer, so it gets called by the Controller Layer (although this is out of the scope at this point in time).
- It uses another object to do it’s thinking - this object is the other half of the “Tag Team” - The View Helper.
The View Helper Object
By providing an extra layer of separation within the View Layer - The Template View will be where your mark up will go and will mostly look like our first example - script 1.1.
This is important because it prevents complicated display logic from being included within the Template View.
The Template View uses a View helper to access data (model and request data for example). The Template View is blind to the system and only knows the View Helper’s API and perhaps the factory methods it provides.
Unlike it’s counterpart, the View Helper is smart and knows a little bit about the system. I pass TOTAL control to a View Helper and let the View Helper decipher what it needs and what it gives the Template View Access to in the form of public methods.
As a quick example, let’s refactor the crappy code in script 1.2 and write it as a Template View / View Helper implementation. Let’s make believe that we are creating a view for displaying news.
As a quick disclaimer, keep in mind that the following are more “proof of concept” type code and examples. For simplicity and clarity’s sake, I did not post examples of the “View” object which makes it possible to access the helper from the Template View nor did I post examples of what a Model would look like - it’s outside the scope of this entry at this stage.
Putting it all together with a Generic View object and the Service Locator
The View Helper Service Locator
The Service Locator is basically a Registry Object with the ability to Create objects for you. Same interfaces as the Registry, but includes a factory for objects. I’ll leave out the details, but I’ll include it here for clarity purposes.
There are many other details I’ve left out here, for example, getting the connection to the locator (I use another locator to do this). Also, figuring out paths, I have a loader object to do this. If I include these in the example, the scope will be too big and this post will be too long, so in an effort to keep things focussed on the View Helper and Template View, I thought I’d just skim over some examples. :)
class ViewHelperLocator
{
protected $_cache = array();
protected $_connection;
public function __construct($connection)
{
$this->_connection = $connection;
}
public function getHelper($helper)
{
// somehow figure out how to get the helper path.
$helper = strtolower($helper);
if (!array_key_exists($helper, $this->_cache)) {
require $helper . ‘.php’; // this is just an example
$this->_cache[$helper] = new $helper($this->_connection);
}
return $this->cache[$helper];
}
public function setHelper($helper, $object)
{
$helper = strtolower($helper);
$this->_cache[$helper] = $object;
}
}
A very incomplete example - no error handling or checking - but it should paint the intent of this object. Basically, when you call the locator’s getHelper() method, it checks its protected cache and if there is no entry, it will create one for you and return the instance.
The Generic View
While other options are available to give the Template View access to the View Helper (ie static methods, singleton etc), I’ve decided to further complete the example by providing a simple generic View Class, I see it as a handler for the Template View. It bridges the gap between Template View and View Helper by providing simple methods like getHelper() which in the example below locates a View Helper using a helper factory or Service Locator.
I’ve also provided some other helpful methods such as render() and getContent() so that objects in the Controller Layer can access content WHEN they want it.
class View
{
protected $_template;
protected $_locator;
protected $_content;
public function __construct(ViewHelperLocator $locator, $template)
{
$this->_locator = $locator;
$this->_template = $template;
}
public function getHelper($helper)
{
return $this->_locator->getHelper($helper);
}
public function render()
{
ob_start();
include $this->_template;
$this->_content = ob_get_clean();
}
public function getContent()
{
return $this->_content;
}
}
The View Helper
class NewsViewHelper
{
public function __construct($connection)
{
$this->_model = new NewsModel($connection);
// let’s just make believe that we are good and have separated our DB logic from the model
}
public function getTitle()
{
if ($this->_model->getTitle()) {
return $this->_model->getTitle();
} else {
return ‘No Page Title’;
}
}
public function listSomeTable()
{
$HTML = ‘<h2>No records to display</h2>’;
while ($row = $this->_model->getList()) {
$HTML .= ‘<h2>’.$row->heading. ‘</h2>’;
$HTML .= ‘<p>’.$row->summary.‘</p>’;
}
return $HTML;
}
}
The Template View
$helper = $this->getHelper(‘NewsViewHelper’); // I am using a temp variable as I do not want to be typing $this->getHelper(’NewsViewHelper’)->listSomeTable() to access helper methods
<html>
<head>
<title><?php echo $helper->getTitle(); ?></title>
</head>
<body>
<?php echo $helper->listSomeTable(); ?>
<hr />
<?php echo $helper->someOtherCrap();?>
</body>
</html>
As you can see, all I’ve done is encapsulated the complicated presentation logic into nice little public accessors from the View Helper which pulls the data it needs from the model.
This leaves you with a cleaner template and keeps complicated logic such as Iteration loops and conditionals out of the Template View (Yes I know they’re not THAT difficult or complicated, but they are complicated if you compare them to a single echo statement).
Conclusion
Glancing over at Zandras PHP 5 Objects Patterns and Practice, I see that he also uses the View Helper as a container to access objects that the Template View will need to use. In his example, he uses the View Helper object to call the request object. Such variations are feasable too.
To conclude - A View Helper object is basically another object which exists between the Template View itself and the rest of the System. By adding the extra layer, we separate presentation logic from mark up and this separation further simplifies access to business data.
on Friday, April 20th, 2007 at 1:33 am:
You have a gift of just explaining things. I must have read so many posts and articles on Template View implementations in php and none of them sunk in. Your example was nice and straight forward. Thank you :)
on Thursday, April 26th, 2007 at 1:46 pm:
No problems, I’m glad it helped you out somewhat. :)
on Saturday, September 8th, 2007 at 2:16 pm:
Hello
At you the excellent site, a lot of useful info and good design, thank.
Bye
on Wednesday, September 12th, 2007 at 2:05 am:
Thank you in turn for the feedback.
on Tuesday, October 9th, 2007 at 8:31 pm:
doesnt it go recursive, when i call get getHelper on locator and i supposed locator to be the the class viewer itself, what is to be stored in locator variable? which object i call with $this->_locater, the viewer object? and where is template view code stored in?
thanks in advance
on Wednesday, October 10th, 2007 at 10:23 am:
Hi Frank,
No recursion occurs here at all, I think the source of your confusion is that you are thinking that the “getHelper()” method in the Generic View and the “getHelper()” method in the locator are coming from the same object. They most certainly are not. What’s happening here is that I have encapsulated the call to $this->_locator->getHelper() with a method within the Generic View, so that I won’t have to type in $this->_locator->getHelper() all the time. The “getHelper” method in the view object is merely for convenience.
The $locator variable is actually another object called “Service Locator” that handles object creation for you and holds instances of classes made before hand. A Service Locator is just like a registry but knows how to create objects (factory). So if in the example above, I use a Service Locator which knows exactly what a View Helper needs to be instantiated and caches it for later use.
I’ll update the example above for you to make it a little clearer.
Regards,
R. Villar David.
on Sunday, October 14th, 2007 at 7:14 am:
thanks :) now its a little bit clearer, but i have to study other patterns to comprehend it as a whole. ill check registry pattern first, good work
on Tuesday, October 23rd, 2007 at 11:10 pm:
No problems. If you have any problems you can always contact me through the contact form on this site.
Regards,
R. Villar David