PHP Template Method Pattern: Geolocation Encapsulated

bostonI was invited to speak at on April 22 at Microsoft’s NERD Center in Boston for Month 4 of Boston PHP’s 200 Days of Code. The Advanced track of 200 Days of Coding is going through Larry Ullman’s book, PHP Advanced & OO Programming (3rd ed), and I’ll be talking about materials from Chapters 8-10. However, with a little over an hour, I am using Occam’s razor to keep things focused, pertinent and related to the relevant chapters. Chapter 10 is about Networking with PHP, and by way of preview, I thought I’d take the material that Larry has on geolocation, and put it into an OOP structure using the Template Method design pattern. I also made a number of other modifications for which Larry cannot be blamed! Go ahead and Play the program to see what it does and Download the code. (The text window defaults to sandlight.com but you can add any URL you want.)
PlayDownload

The Magical Template Method

The first thing I did was to set up the geolocation app with a Template Method. You can see previous discussions and examples of the Template Method on this blog, but I wanted to include the class diagram the Gang of Four used to see how simple but elegant this pattern actually is. Figure 1 shows this subtle but powerful method:

Figure 1: Template Method class diagram

Figure 1: Template Method class diagram

The nice thing about this design pattern is that it has lots of uses as you may have already seen on this blog. However, the same simple principle is used: Abstract methods from an abstract class are implemented in a concrete method from the same abstract class. What the Template Method does is to provide a blueprint for the order of the methods to be used with the exact content dependent on the intended use.

So, starting with the abstract class, you can see how this implementation works:

<?php
abstract class ILocatorTemplate
{
    protected $url, $info, $data, $ip, $loc;
    protected $package=array();
    protected abstract function getLocation();
    protected abstract function bundle();
 
    //The Template Method
    protected function templateMethod()
    {
        $this->getLocation();
        $this->bundle();
    }
}
?>

A number of protected properties are first declared, including an array object, $package. Next the two primitive operations are declared, getLocation() and bundle(). The former is for getting the geolocation of a URL and the second for placing that information into the $package object. That’s it! All that’s left to do is to implement the abstract class.

The Locator class

The concrete implementation of the ILocatorTemplate adds content to the properties and concrete operations to the two abstract methods.

<?php 
class Locator extends ILocatorTemplate
{
    public function doLocate($place)
    {
        $this->loc = $place;
        $this->templateMethod();
        return $this->package;
    }
 
    protected function getLocation()
    { 
        $this->ip = gethostbyname($this->loc);
        $this->url = 'http://freegeoip.net/csv/' . $this->ip;
 
        $this->info = fopen($this->url, 'r');
        $this->data = fgetcsv($this->info);
        fclose($this->info);
    }
 
    protected function bundle()
    {
        $this->package['IP']=$this->data[0];
        $this->package['CountryID']=$this->data[1];
        $this->package['Country']=$this->data[2];
        $this->package['StateID']=$this->data[3];
        $this->package['State']=$this->data[4];
        $this->package['City']=$this->data[5];
        $this->package['Zip']=$this->data[6];
        $this->package['latitude']=$this->data[7];
        $this->package['longitude']=$this->data[8];
    }
}
?>

The doLocate() method holds the URL passed by the user. That is placed into one of the properties declared in the abstract class, $loc. Next, the $templateMethod() fires and it, in turn, launches first the getLocation() method and then the bundle() method. It doesn’t matter what is in those methods because they were defined abstractly. Therefore, any abstract method defined as part of template method will launch regardless of its implementation, as long as it adheres to the signature form in the abstract class. The getLocation() method pretty much follows the steps Larry lays out in Chapter 10. It uses the freegeoip.net Web service which returns CSV data with the location information.

The bundle() method transfers the data from the $data array send by the Web service into an associative array, $package. The keys in the associative array will serve as labels for the data once processed in the Client class.

The last step in the process is to return the $package containing an associative array with descriptive keys and location information. That’s it….but there is one more thing before we turn to the UI and client.

The Hollywood Principle

The Template Method exemplifies a larger design pattern principle called the Hollywood Principle, simply stated,

Don’t call us. We’ll call you.

It refers to how a parent class (ILocatorTemplate) call the operations of a subclass (Locator) and not the other way around. The templateMethod() function is a concrete method from the parent class, and both the getLocation() and bundle() methods are implementations of the child class, Locator. So, the parent class method calls the child class implementations; not vice versa. This fundamental principle will help keep your PHP OOP from getting tangled up.

The HTML5 UI and Client

The HTML5 UI provides a single text window for the user to place a URL to be located, the names of the class to be called (Locator) and the method to call (doLocate) in hidden input elements, and an iframe to get the results. It’s pretty basic:

<!DOCTYPE html>
<html>
<head>
    <link rel="stylesheet" type="text/css" href="whoyou.css">
    <title>Find URL Info</title>
</head>
 
<body>
    <header><h3>Find Location Information</h3></header>
    <form action="Client.php" method="post" target="feedback">
        <input type="text" name="url" value="sandlight.com">&nbsp;URL<br />
        <input type="hidden" name="classNow" value="Locator"><br />
        <input type="hidden" name="method" value="doLocate"><p />
        <input type="submit" value="Find Info"><br />
    </form>
<iframe name="feedback" width="240" height="200">feedback</iframe>
</body>
</html>

The Client is the linchpin in the UI—Client—Request model used on this blog. The HTML5 UI passes the URL from the text element in a superglobal, and it’s added to the method passed in a different superglobal.

<?php
error_reporting(E_ALL | E_STRICT);
ini_set("display_errors", 1);
// Autoload given function name.
function includeAll($className)
{
    include_once($className . '.php');
}
//Register
spl_autoload_register('includeAll');
 
class Client
{
    private static $locator;
    private static $locationData=array();
    //client request
    public static function request()
    {
      self::$locator=new $_POST['classNow'];
      self::$locationData=self::$locator->{$_POST['method']}($_POST['url']);
 
      //Display
      foreach(self::$locationData as $key => $value)
      {
        echo "$key : $value<br />";
      }
    } 
}
Client::request();
?>

The display for the iframe that contains the data is simply crunched out using a foreach loop on the passed associative array. The keys have the labels, and the values the location details.

Come to Boston!

If you live in or near Boston, come on up (or down) on Wednesday, April 22, 2015. There’s free pizza at 6 pm and the Advanced group meets after the pizza. Check out this notice on the Web. I’d like to meet you all!

Share

Copyright © 2015 William Sanders. All Rights Reserved.

0 Responses to “PHP Template Method Pattern: Geolocation Encapsulated”


  • No Comments

Leave a Reply