PHP Composite View Design Pattern: Introducing the Key Concepts

The Composite View design pattern offers users the versatility of handling single objects and collections through the same interface. But some programmers hesitate to use it due to its tricky implementation. Hesitate no longer; this multi-part series will take you step by step through some of the best ways to use the Composite View design pattern, complete with code samples to show you the way.

Regardless of their specific implementation, which may vary from a programming language to another (and even across different applications), one additional advantage that design patterns offer is that their names give you a pretty clear idea of what they can be used for. Good examples of this can be found when building Singletons, Factories, Facades and so forth — it’s easy to guess what kind of problem they’re designed to tackle, even without seeing how they’re concretely applied.

This concept holds true for many other popular patterns, including the always venerable “Composite.” As you may know, the Composite pattern can be used to handle single objects and collections of them (also known as composites) through the same interface. While the functionality of Composite permits you to perform the aforementioned task in a elegant and efficient way, and it’s also a pristine example of favoring Composition over Inheritance, its implementation is very often confusing.

The good news about Composite is that its underlying logic is incredibly simple to grasp, and it’s present nearly everywhere. Want a concrete example that sheds some light on the topic? Well, say that you’re building an application comprised of a bunch of classes that extend a single abstract parent. To get the application up and running, each class must be bootstrapped individually via a hypothetical method called “bootstrap().” Still with me? Great.

Since you’re a clever programmer who likes to abstract things away, you build the classes in such a way that they can be bootstrapped separately or in conjunction. In doing so, client code calling the “bootstrap()” method could bootstrap a single class, or a collection of them, behind the scenes. Isn’t that nice? Well, feel free to congratulate yourself, because you’ve just implemented a Composite!

What’s more, a similar approach can be followed when working with views, something called in programming jargon the “Composite View” pattern. However, when used specifically in PHP, it allows you to render one or multiple view templates with a single method call, thus making it easy to work with “partials” (coined in the RoR world) and master layouts at the same time.

Considering the flexibility that the Composite View pattern offers to PHP developers, in this article series I’m going to demonstrate how to implement it via some approachable examples. You’ll be able to use them as standalone modules or add them to your existing MVC layer. Let’s get started!

{mospagebreak title=Defining an abstract composite view class}

As the old proverb says, a long walk always begins with a single step. In keeping with this idea, the first thing I’m going to do to implement the Composite View pattern will be to build an abstract parent class. This class will encapsulate the functionality and structure of generic view objects. Later on, refined implementations of this parent will be responsible for handling one and multiple view objects through the same interface.

With that said, here’s how this abstract parent looks in its initial stage: 

(AbstractView.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]);
        }
    }
}

 

(ViewException.php)


<?php

class ViewException extends Exception{}

As you can see, the above “AbstractView” class is quite easy to follow. It simply implements the magic “__set()” and “__get()” PHP methods to add and fetch undeclared view properties dynamically, which are stored in a protected array for further processing. The class also defines a mutator and an accessor for its “$_template” property, which can be used for handling the template file that the view class is going to render.

While this abstract parent is currently pretty functional, it still isn’t capable of manipulating single and multiple views via the same interface, in accordance with the commandments imposed by the Composite pattern. So it’s time to provide the class with this ability. We’ll achieve this by defining a couple of abstract methods.

The signatures of these methods will be shown in the following segment, so click on the link below and keep reading. 

{mospagebreak title=Defining methods for adding and removing views}

As I said in the preceding section, it’s necessary to provide the previous abstract parent class with an interface that permits it to add and remove view objects, so that they can be handled either individually or in conjunction. Since this functionality should be added by concrete implementation of the pertinent parent, in this case the interface will be defined by a couple of abstract methods, called “addView()” and “removeView()” respectively.

Here’s how the earlier “AbstractView” class looks after adding these methods:
 
(AbstractView.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);
}   

There you have it. Even though the brand new “addView()” and “removeView()” methods have been declared abstract, their signatures do allow you to have a more accurate idea of how the Composite View pattern does its thing. The methods accept other view objects for further aggregation or removal, therefore putting in evidence the use of Composition over Inheritance.

If you still don’t have a clue as to how a single view and collections of them can be handled indiscriminately via the same interface, don’t feel concerned. Things will become clear when I show you the definition of the subclasses derived from the previous abstract parent.

The only thing that remains undone now is adding to this parent a method that permits it to render the assigned view template on screen. This will be done in the following section, so go ahead and read the next few lines. 

{mospagebreak title=Finish sample class: add a method for rendering view templates}

To complete the earlier abstract composite view class, we must add to it a method that allows it to render its associated template on screen. This simple method will be called, not surprisingly, “render().” Its implementation has been included below in the class’s source code. Check it out:    

(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

As you can see above, the “render()” method is responsible for performing two well-differentiated tasks. First, it populates the view template with the values assigned to the class properties created “magically,” and second, it returns the parsed template to client code for further processing. Of course, it’s clear to see that the logic of this method can be improved in many clever ways, but for the sake of clarity I’m going to keep it this simple.

Now that the development of the “AbstractView” class has been completed, it should be a bit easier for you to understand how concrete implementations of this class will be capable of rendering one and composite views through the same “render()” method. However, if this process still remains confusing to you, don’t worry; it’ll be covered in detail in the next tutorial. 

Final thoughts

In this introductory part of the series, I went through the definition of an abstract composite view class. This class not only encapsulates the functionality of generic view objects, but defines the interface required for adding and removing the objects in question. Naturally, this capability must be implemented in some way by a concrete subclass, right?

To fit this requirement, in the upcoming tutorial I’m going to create the aforementioned subclass. This should help you understand more clearly how to render single and multiple views via the “render()” method implemented by the abstract parent created before.

Don’t miss the next part!

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