Template View and View Helper Design Patterns in PHP (updated v2)

April 18th, 2007 by rvdavid Leave a reply »

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

// script 1.1

<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

// script 1.2
$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.

// generic view object
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

// 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

// Template View (script 1.3)

$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.

if you enjoyed this post, make sure you subscribe to my RSS feed!
You can also follow me on Twitter here.

No related posts.

Advertisement

12 comments

  1. Linda says:

    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 :)

  2. rvdavid says:

    No problems, I’m glad it helped you out somewhat. :)

  3. sopitikoj says:

    Hello

    At you the excellent site, a lot of useful info and good design, thank.

    Bye

  4. rvdavid says:

    Thank you in turn for the feedback.

  5. Frank says:

    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

  6. rvdavid says:

    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.

  7. Frank says:

    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

  8. rvdavid says:

    No problems. If you have any problems you can always contact me through the contact form on this site.

    Regards,

    R. Villar David

  9. San says:

    Hi,
    Could you please include the code to call this View from a page? if you have working code that will be better.
    Regards,
    San.

  10. San says:

    class :ViewHelperLocator
    Function : getHelper($helper)

    Typos: return $this->cache[$helper]; (underscore is missing for cache)

    this took my time :-)

  11. San says:

    Hello ,
    I tried to make it work like the following, but I got the error!:
    Fatal error: Allowed memory size of 33554432 bytes exhausted (tried to allocate 33292271 bytes) in C:\xampp\htdocs\view\NewsViewHelper.class.php on line 23

    require_once(‘ViewHelperLocator.class.php’);
    require_once(‘View.class.php’);

    $connection = mysql_connect(‘localhost’, ‘root’, ”);
    mysql_select_db(‘floorplans’, $connection);

    $viewHelperLocator = new ViewHelperLocator($connection);
    $view = new View($viewHelperLocator, ‘template.php’);
    $view->render();

    I’m interested in this code working, I want to create site without any framework, but similar code!
    :-)
    San.

    • rvdavid says:

      Sorry you’ve had so much trouble using the example code.

      Firstly, you are getting the error because the memory limit is set to 32M – look for memory_limit in your php.ini file and change it to something like 128M.

      From reading your comments, it looks like you’re making the transition from procedural to OOP.

      When you become more experienced with OOP, you’ll look at the code snippets here and you’ll hate it.

      Use the examples and concepts presented here, to familiarise yourself with OOP (using classes / objects) rather than a recipe to building web apps / sites.

      In addition, this is a very old post (3 years old!) Since then, a lot of frameworks have matured and are production ready.

      I highly recommend that you pick one up.

      I’m using Zend Framework (http://framework.zend.com), have successfully built 3 web applications on it, and I am very happy with the results.

      Good luck with your project.

Leave a Reply

Notify me of followup comments via e-mail. You can also subscribe without commenting.