Home arrow PHP arrow Plug-in Pattern in PHP and JavaScript

Plug-in Pattern in PHP and JavaScript

In this second part of the series, I demonstrated how to use the “Plug-in” pattern for developing a fully-pluggable application that renders different types of elements on screen. The “plug-ins” passed to the client renderer will be objects that generate basic HTML/JavaScript code and nothing else.

TABLE OF CONTENTS:
  1. Plug-in Pattern in PHP and JavaScript
  2. Building a class to display JavaScript alert boxes
By: Alejandro Gervasio
Rating: starstarstarstarstar / 2
January 25, 2011

print this article
SEARCH DEV SHED

TOOLS YOU CAN USE

advertisement

Although the term is like a wild card used in fields other than software engineering, “Plug-in” is also the name of a design pattern which permits you to extend the functionality of a system (an application, a library, or a full-blown MVC framework) by means of a clever use of Composition and generic interfaces. These can be native, or in the form of abstract classes.

Like any other pattern, “Plug-in” is language-agnostic. This implies that it can be implemented in any programming language, including PHP. In keeping with this concept, in the introductory part of this series I went through the development of a rather primitive PHP application. Its main area of responsibility was to display, through a single client rendering class, different types of HTML objects, such as divs and paragraphs.

Thanks to the use of the “Plug-in” pattern, though, injecting each object into the internals of the pertinent client class and then rendering it on screen was as simple as replacing one Lego block with another. Not too bad, huh?

To fully honor the pattern’s name, however, the aforementioned application should be capable of rendering any type of object, not just the couple of HTML widgets referenced before. Well, to demonstrate this concept from a practical standpoint, in this second chapter of the series I’m going to define a brand new class, which will be tasked with rendering simple JavaScript alert boxes.

If you ask me what’s so special about this class, I have to say… nothing, except for a subtle detail worth noting: due the flexibility of the “Plug-in” pattern, the class will be passed to the client renderer and displayed on the browser without having to alter a single portion of the source classes developed so far.

So, do you want to see how this entirely new class will be built and “plugged in” to the existing infrastructure of this sample rendering application? Then don’t hesitate anymore; begin reading!

Review: a basic implementation of the “Plug-in” pattern

Before I show you the definition of the alert box class mentioned in the introduction, and how it will be afterward plugged in to the corresponding client rendering class, it’d be useful to review the example developed in the previous part of the series, It basically demonstrated the functionality of the “Plug-in” pattern when used with two different HTML objects.

Having said that, here’s the common interface implemented by the originating classes of these objects:

(Render/Renderable.php)

<?php

namespace Render;

interface Renderable
{
    public function render(); 
}

Since the “Renderable()” interface only declares a single “render()” method, look at the following classes. The first one is an abstract parent that defines the structure and behavior of generic HTML elements, while the other two are implementers of the interface, charged with rendering divs and paragraphs respectively:

(Html/AbstractHtmlElement.php)

<?php

namespace Html;

abstract class AbstractHtmlElement
{
    protected $_content;
    protected $_id;
    protected $_class;
   
    /**
     * Constructor
     */
    public function __construct($content, $id = '', $class = '')
    {
        if (is_string($content)) {
           $this->_content = $content;
        }
        if (is_string($id) && !empty($id)) {
            $this->_id = $id;
        }
        if (is_string($class) && !empty($class)) {
            $this->_class = $class;
        }   
    }   
}

 

(Html/Div.php)

<?php

namespace Html;
use Render;

class Div extends AbstractHtmlElement implements RenderRenderable
{
    /**
     * Render the Div element
     */
    public function render()
    {
        $html = '<div';
        if ($this->_id) {
            $html .= ' id="' . $this->_id . '"';
        }
        if ($this->_class) {
           $html .= ' class="' . $this->_class . '"';
        }
        $html .= '>' . $this->_content . '</div>' . "n";
        return $html;
    }
}

 

(Html/Paragraph.php)

<?php

namespace Html;
use Render;

class Paragraph extends AbstractHtmlElement implements RenderRenderable
{
    /**
     * Render the Paragraph element
     */
    public function render()
    {
        $html = '<p';
        if ($this->_id) {
            $html .= ' id="' . $this->_id . '"';
        }
        if ($this->_class) {
           $html .= ' class="' . $this->_class . '"';
        }
        $html .= '>' . $this->_content . '</p>' . "n";
        return $html;
    }
}

By now you’ve grasped the logic driving the earlier HTML classes, so I suggest you pay attention to the implementation of the following one. It is a composite capable of displaying on screen any “renderable” object previously added through its “addElement()” method.

The client class looks like this:

(Render/Renderer.php)

<?php

namespace Render;

class Renderer
{
    protected $_elements = array();
   
    /**
     * Add a single renderable element
     */
    public function addElement(Renderable $element)
    {
        $this->_elements[] = $element;
        return $this;
    }
   
    /**
     * Remove a renderable element
     */
    public function removeElement(Renderable $element)
    {
        if (in_array($element, $this->_elements, true)) {
            $elements = array();
            foreach ($this->_elements as $_element) {
                if ($element !== $_element) {
                    $elements[] = $_element;
                }
            }
            $this->_elements = $elements;
        }
    }
   
    /**
     * Add multiple renderable elements
     */
    public function addElements(array $elements)
    {
        if (!empty($elements)) {
            foreach ($elements as $element) {
                $this->addElement($element);
            }
        }
    }
   
    /**
     * Render all the inputted renderable elements
     */
    public function render()
    {
        $output = '';
        if (!empty($this->_elements)) {
            foreach ($this->_elements as $_element) {
                $output .= $_element->render();
            }
        }
        return $output;
    }    
}

While at first glance it seems that the above “Renderer” class does nothing particularly interesting, except render some inputted elements, this is a misconception, trust me. Even at a basic level, this class gets the pieces required by the “Plug-in” pattern working together. On the one hand, it uses Composition to inject the elements in question, while on the other hand it takes advantage of an interface (a simple contract, in this case) to make sure that those elements are really “renderable.”

If this concept sounds somewhat confusing to you, take a look at the following code snippet, which shows how to display on the browser the markup corresponding to the “Div” and “Paragraph” class just defined:    

<?php

use HtmlDiv as Div,
    HtmlParagraph as Paragraph,
    RenderRenderer as Renderer;
   
// include the autoloader
require_once 'Autoloader.php';
Autoloader::getInstance();

// create some HTML elements
$div = new Div('This is the sample content for the div element.', 'one_id', 'one_class');
$par = new Paragraph('This is the sample content for the paragraph element.', 'another_id', 'another_class');

// create the renderer and add the previous elements to it
$renderer = new Renderer;
echo $renderer->addElement($div)
              ->addElement($par)
              ->render();

/* displays the following

<div id="one_id" class="one_class">This is the sample content for the div element.</div>
<p id="another_id" class="another_class">This is the sample content for the paragraph element.</p>

*/

For the sake of brevity, in this case I omitted the definition of the autoloader, as this was covered in detail in the previous part of the series. This shouldn’t be an obstacle, though, to understanding how the previous script works. All that it does is input a div and a paragraph object into the client renderer class and display the resulting HTML on screen.

Beyond the simplicity of this example, the beauty of it is that the client renderer accepts any type of object, as long as it’s an implementer of the “Renderable” interface. But what does this buy us? Well, if I ever wanted to write a separate class that renders a type of content that isn't HTML and plug it into the renderer, the process would be dead simple.

Considering that the best way to demonstrate the “pluggability” of this sample application is by adding  such a class to it, in the next section I’m going to create a new class. It will be charged with rendering basic JavaScript alert boxes. Best of all, injecting an instance of this class into the previous renderer won’t require us to modify or refactor any section of its existing source code.

Now, to see how this JavaScript class will be created, click on the link 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: