Home arrow PHP arrow PHP: Rendering Web Pages Using the Composite View Design Pattern

PHP: Rendering Web Pages Using the Composite View Design Pattern

Welcome to the conclusion of a five-part series on the Composite View design pattern. This article will focus on a way to make use of this design pattern when you're building dynamic web pages. It involves a simple two-step rendering process.

TABLE OF CONTENTS:
  1. PHP: Rendering Web Pages Using the Composite View Design Pattern
  2. Creating some basic web page sections
By: Alejandro Gervasio
Rating: starstarstarstarstar / 3
September 01, 2010

print this article
SEARCH DEV SHED

TOOLS YOU CAN USE

advertisement

As you probably know, one of the great commandments of good object-oriented programming says that whenever possible, Composition must be used over Inheritance, as the latter is an overrated way of reusing code. While itís fair to admit that this principle should be used with due caution and, for obvious reasons, applied in the appropriate situations, thereís a case where it really shows all of its splendor.

Yes, as the name of this article suggests, this time Iím talking about the implementation of Composite View, a flexible design pattern derived from its cousin Composite. When used for web development, Composite View allows you to manipulate single templates (in most cases in the form of HTML pages) and collections of them via the same interface.

Naturally, if youíve already read all of the preceding tutorials in this series, itís probable that you now have a clear idea of how to create a few composite view classes with PHP, and how to use them for rendering dynamic web pages with a single method call. I discussed in detail how to accomplish this in the previous installment.

Even though rendering several templates through only one class method is by far the major strength of a ďtypicalĒ Composite View, itís also possible to use the pattern in a slightly different manner and obtain nearly the same results, at least when creating dynamic web pages. To demonstrate how to create this interesting variation of the pattern, in this last chapter of the series Iím going to utilize the sample classes defined previously to generate a basic (X)HTML document, where each of its sections will be rendered individually before being embedded into a master layout.

Want to see how this will be done in a few simple steps? Then start reading right now!         

A brief look at the composite view classes defined previously

As I said in the introduction, itís feasible to use the composite view classes created in previous chapters of this series to build a dynamic (X)HTML page by using a two-step rendering process. But, before I start demonstrating how to achieve this, Iíd like to spend a few moments reintroducing the definitions of the classes.

With that said, hereís the abstract parent class, tasked with modeling the structure and behavior of generic view objects:

(AbstractView.php)


<?php

abstract class AbstractView
{
    protected $_template = 'default.php';
    protected $_properties = array();

    // constructor
    public function __construct($template = '', array $data = array())
    {
        if ($template !== '') {
            $this->setTemplate($template);
        }
        if (!empty($data)) {
            foreach ($data as $name => $value) {
                $this->$name = $value;
            }
        }
    }
   
    // set a new view template
    public function setTemplate($template)
    {
        $template = $template . '.php';
        if (!file_exists($template)) {
            throw new ViewException('The specified view template does not exist.');  
        }
        $this->_template = $template;
    }
     
    // get the view template
    public function getTemplate()
    {
        return $this->_template;
    }
     
    // set a new property for the view
    public function __set($name, $value)
    {
        $this->_properties[$name] = $value;
    }

    // get the specified property from the view
    public function __get($name)
    {
        if (!isset($this->_properties[$name])) {
            throw new ViewException('The requested property is not valid for this view.');     
        }
        return $this->_properties[$name];
    }

    // remove the specified property from the view
    public function __unset($name)
    {
        if (isset($this->_properties[$name])) {
            unset($this->_properties[$name]);
        }
    }
   
    // add a new view (implemented by view subclasses)
    abstract public function addView(AbstractView $view);
   
    // remove a view (implemented by view subclasses)
    abstract public function removeView(AbstractView $view);
   
    // render the view template
    public function render()
    {
        if ($this->_template !== '') {
           extract($this->_properties);
           ob_start();
           include($this->_template);
           return ob_get_clean();
        }
    }
}// End AbstractView class

 

<?php

class ViewException extends Exception{}

Since the driving logic of the above abstract parent class was discussed in depth before, Iím not going to waste your time (and mine) explaining again how it works. Instead, I suggest you look at the definitions of the following two classes, which are responsible for handling view objects collectively and individually. Here they are:

(View.php)


<?php

class View extends AbstractView
{
    protected $_views = array();
       
    // factory method (chainable)
    public static function factory($view, array $data = array())
    {
        return new self($viewfile, $data);
    }
   
    // add a new view object
    public function addView(AbstractView $view)
    {
        if (!in_array($view, $this->_views, TRUE)) {
            $this->_views[] = $view; 
        }
        return $this;
    }
   
    // remove an existing view object
    public function removeView(AbstractView $view)
    {
        if (in_array($view, $this->_views, TRUE)) {
            $views = array();
            foreach ($this->_views as $_view) {
                if ($_view !== $view) {
                    $views[] = $_view;
                }
            }
            $this->_views = $views;
        }
        return $this;
    }
   
    // render each partial view (leaf) and optionally the composite view
    public function render()
    {
        $innerView = '';
        if (!empty($this->_views)) {
            foreach ($this->_views as $view) {
                $innerView .= $view->render();
            }
            $this->content = $innerView;
        }
        $compositeView = parent::render();   
        return !empty($compositeView) ? $compositeView : $innerView;
    }  
}// End View class

 

(Partial.php)


<?php

class Partial extends AbstractView
{
    // throw an exception as a partial view (leaf) cannot add another view
    public function addView(AbstractView $view)
    {
        throw new ViewException('A partial view cannot add another view.');  
    }
   
    // throw an exception as a partial view (leaf) cannot remove another view
    public function removeView(AbstractView $view)
    {
        throw new ViewException('A partial view cannot remove another view.');  
    }   
}// End Partial class

From the above code samples, itís clear to see how the concrete ďViewĒ class is capable of rendering the templates associated with single and multiple view objects through a unique method. Again, this puts in evidence how the Composite View pattern makes a clever use of Composition, instead of relying heavily on the benefits provided by Inheritance.

And now that you've learned how the earlier sample classes do their business, I'm going to show the source code of the autoloader created in the preceding chapter. It can be used for lazy-loading classes  via the SPL stack offered natively by PHP.

Hereís how the pertinent autoloader was originally created: 

(Autoloader.php)


<?php

class Autoloader
{
    private static $_instance;
   
    // get the Singleton instance of the autoloader
    public static function getInstance()
    {
       if (!self::$_instance) {
           self::$_instance = new self;
       }
       return self::$_instance;
    }
   
    // private constructor
    private function __construct()
    {
        spl_autoload_register(array($this, 'load')); 
    }
   
    // prevent cloning instance of the autoloader
    private function __clone(){}
    
    // autoload classes on demand
    public static function load($class)
    {
        $file = $class . '.php';
        if (!file_exists($file)) {
            throw new ClassNotFoundException('The file ' . $file . ' containing the requested class ' . $class . ' was not found.');
        }
        include $file;
        unset($file);
        if (!class_exists($class, FALSE)) {
            throw new ClassNotFoundException('The requested class ' . $class . ' was not found.');
        }
    }  
}// End Autoloader class

 

<?php

class ClassNotFoundException extends Exception{}

Well, youíll have to agree with me that the implementation of the above ďAutoloaderĒ class is very easy to follow, as it simply uses the SPL stack for loading classes on demand without having to use multiple PHP includes. That was simple to code and read, wasnít it?

So far, so good. Now that I've reintroduced all of the sample classes defined so far, itís time to demonstrate how to use them together in a truly creative way. We're going to create a dynamic web page by using the aforementioned two-step rendering process.

Thatís the topic that I plan to discuss in the following section, so click on the link that appears below and keep reading.



 
 
>>> More PHP Articles          >>> More By Alejandro Gervasio
 

blog comments powered by Disqus
escort Bursa Bursa escort Antalya eskort
   

PHP ARTICLES

- Hackers Compromise PHP Sites to Launch Attac...
- Red Hat, Zend Form OpenShift PaaS Alliance
- PHP IDE News
- BCD, Zend Extend PHP Partnership
- PHP FAQ Highlight
- PHP Creator Didn't Set Out to Create a Langu...
- PHP Trends Revealed in Zend Study
- PHP: Best Methods for Running Scheduled Jobs
- PHP Array Functions: array_change_key_case
- PHP array_combine Function
- PHP array_chunk Function
- PHP Closures as View Helpers: Lazy-Loading F...
- Using PHP Closures as View Helpers
- PHP File and Operating System Program Execut...
- PHP: Effects of Wrapping Code in Class Const...

Developer Shed Affiliates

 


Dev Shed Tutorial Topics: