PHP: Creating Single View Objects with the Composite View Design Pattern

In this third part of a series on the Composite View pattern, I develop a concrete class derived from the abstract parent built previously. This new class will be responsible for creating simple view objects.

The tandem composed of the Composite and Decorator design patterns offers an example that shows where the use of Composition can help in building flexible applications. While decorators are normally used for extending the functionality of objects that are of the same type without having to appeal to Inheritance, Composites provide an elegant and efficient paradigm that allows programmers to manipulate single objects and collections of them through the same interface.

There’s a plethora of situations where Decorators are utilized successfully in the development of PHP-based programs, and more specifically in the construction of versatile user interfaces on web pages. But what about Composites? Well, there’s a relative of Composite called “Composite View,” which can be used for rendering single and multiple (X)HTML templates in a very flexible fashion. Simply put, client code consuming a composite view class will be able to manipulate web page sections, and even entire (X)HTML documents, via the same set of methods without being aware of this. That’s a good example of encapsulation, right?

If you’ve already read previous parts of the series, then you’ve seen a couple of concrete ways to implement the Composite View pattern. I started by creating a simple hierarchy of composite view classes, comprised of an abstract parent that defined the structure and behavior of generic view objects. I then created a concrete subclass, which was responsible for handling these objects individually and collectively via a unique rendering method.

To complete this hierarchy, though, it’s necessary to create an additional class. It will be tasked with creating single view objects. So, in this third installment of this series I’m going to show you how to build such a class, which will be an approachable process, believe me.

Now, it’s time to get rid of the dull theory and continue exploring the benefits of using the Composite View pattern in PHP. Let’s go!

Review: a quick summary of the sample classes developed so far

Just in case you still haven’t read the tutorial that precedes this one, where I showed how to create a concrete composite view class derived from the abstract parent mentioned in the introduction, below I included for you the definitions corresponding to these sample classes. This way, you can quickly grasp how they work.

First, here is the abstract parent, which is 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{}

If you study the above “AbstractView” class in detail, you’ll realize that it’s nothing but a simple container that stores the properties assigned to a generic view object, including its associated template file. Of course, its “render()” method is responsible for rendering the template, but only for a single object. However, a typical implementation of a Composite View should be able to render single and multiple templates through the same interface. How can this be done?

Well, the following concrete subclass performs this task in a fairly straightforward fashion. Look at it, please:

(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

There you have it. As you saw before, the previous “View” class is capable of rendering indiscriminately a single template or a collection of them, thanks to the implementation of the inherited “addView()” and “removeView()” methods.

Even though at first glance, a composite view class like the one defined above seems to be pretty pointless, the truth is that its functionality can be cleverly exploited to render multiple web page sections and complete (X)HTML documents via a single method call. But in fact I’m getting ahead of myself, since the full details of how to accomplish this will be covered in upcoming parts of this series.

For the moment, the next thing we must do is create a concrete implementation of the previous “AbstractView” class that allows us to create single view objects in a truly painless way. Precisely this process will be discussed in the next section, so to learn more about it, click on the link below and keep reading.

{mospagebreak title=Handling single view objects}

Be honest and ask yourself how many movies you’ve seen where a character said in a solemn tone: “the hardest part is over.” A lot, right? However, in this case the phrase is not extracted from a Hollywood script; the previous “View” class really does the hard work of handling single and multiple view objects via the same “render()” method. However, there is still a missing piece in this schema that needs to be created, to get the earlier hierarchy of classes up and running.

Yes, as you may have guessed, it’s necessary to derive yet another concrete class from the corresponding abstract parent that only handles single view objects and not composite ones. The following class, which has been called “Partial” does exactly that:

(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

Trust me, I don’t want to sound like I’m bragging, but you’ll have to agree that the definition of the previous “Partial” class is ridiculously simple. It only throws a couple of custom exceptions within the inherited “addView()” and “removeView()” methods. The reason to implement these methods in that way is pretty obvious; the class only handles single view objects and therefore can’t remove or add others. Got this point? Great.

So far, so good. At this stage, the hierarchy of classes required to use the Composite View pattern in a useful fashion has been completed. It’s time to list the classes all together, so you can have them at your disposal in one single place for editing purposes.

This will be done below, so keep reading.     

Showing all of the composite view classes defined previously

As I said above, I included the definitions corresponding to all the sample classes created so far below. This way, you can edit their source code and add your own improvements to them.

First, here’s the abstract parent that encapsulates the functionality 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{}

Having shown the abstract parent, which is seated at the top of this hierarchy of composite view classes, it’s time to list the one that renders single and multiple view objects through the “render()” method discussed previously. Here it is:

(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

And finally, below you’ll find the definition of the concrete “Partial” class, which is tasked with creating single view objects. Check it out:

(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

Mission accomplished. Now that you have all of the composite view classes created in this series available in a single place, feel free to give them a try and see if they really can be used for building web pages by using partial sections and master layouts.

Anyway, if you feel intimidated and don’t know yet how to tackle this process with confidence, don’t feel concerned, since it’ll be covered in depth in the forthcoming tutorial.

Final thoughts

That’s all for now. In this third part of the series, I went through the development of a concrete class derived from the abstract parent built previously, which was charged with creating simple view objects. As you saw, this class isn’t capable of aggregating new objects or even removing existing ones, so the inherited “addView()” and “removeView()” methods simply throw a couple of exceptions when called by client code.

Having already created a hierarchy of composite view classes, the next step we must take is to put these classes into action. This way, you’ll see how flexible they can really be when rendering (X)HTML templates. With that premise in mind, in the following article I’m going to set up a concrete example that will use all of the sample classes defined so far.

Here’s my final piece of advice: don’t miss the next part!

[gp-comments width="770" linklove="off" ]
antalya escort bayan antalya escort bayan