Google’s Closure Compiler Service API: Talking to the API via a PHP Class

In this second part of the series, I develop a concrete PHP class derived from the abstract parent defined in the previous tutorial. This new class implements some refined methods that permit you to interact “face-to-face” with Google’s Closure Compiler Service API in a pretty straightforward fashion.

If the ever-increasing size of your custom JavaScript files has you desperately looking for an application that lets you optimize them through a few simple options, then you should take a close look at Google’s Closure Compiler Service API. This web service released recently by the search company (at least at the time of this writing) will permit you to perform the entire optimization process either manually by using a graphical user interface, or programmatically via POST HTTP requests.

If you’ve read the introductory tutorial of this series, you’re familiar in general terms with the capabilities that the Closure Compiler API offers. In that part I gave a brief overview of the API’s main features, including the ability to specify the level of optimization that will be applied to the target files, and the format (text, XML or JSON) in which the files will be dispatched to the client.

It’s valid to recall that the main objective of this series is to demonstrate, in a step-by-step manner, how to interact with the Closure Compiler Service API using PHP. This process can be ported to other programming languages with minor efforts. In keeping with that premise, in the previous article I went through the development of an abstract PHP class, which encapsulated most of the functionality required to perform HTTP requests to a given host and a TCP port via a set of simple methods.

With that abstract parent already defined, the next step is to create a concrete subclass that is capable of talking directly to the Closure Compiler Service API. This subclass will allow us to automatically optimize multiple JavaScript files easily, without the need to explicitly use the compiler’s GUI.

With that said, it’s time to start building the aforementioned concrete PHP class. Want to see how this will be done? Just keep reading. 

Creating the backend to interact with the Closure Compiler Service API: creating an abstract HTTP request handler class in PHP

As I just explained, my goal here is simply to show how to consume Google’s Closure Compiler Service API using an object-oriented backend composed of a few sample PHP classes. To accomplish this, I first developed an abstract class, which was nothing but an enhanced wrapper of the “fsockopen()” PHP function. The full source code of the class looked like this:   

(HttpRequestHandlerAbstract.php)

<?php

abstract class HttpRequestHandlerAbstract
{
    protected $_data = array();
    protected $_url;
    protected $_port;
    protected $_method;
    protected $_headers = array();
    protected $_responseHeader;
    protected $_responseContent;
   
    // constructor
    public function __construct(array $data, array $settings = array())
    {
        $this->setData($data);
        if (array_key_exists(‘url’, $settings)) {
            $this->setUrl($settings['url']);
        }  
        if (array_key_exists(‘port’, $settings)) {
            $this->setPort($settings['port']);
        }
        if (array_key_exists(‘method’, $settings)) {
            $this->setMethod($settings['method']);
        }
    }
   
    // set the data that will be passed with the request
    public function setData(array $data)
    {
        if (empty($data)) {
            throw new HttpRequestHandlerException(‘The request arguments are not valid.’);
        }
        $this->_data = $data;
        return $this;
    }
     
    // get the specified request data
    public function getData()
    {
        return $this->_data;
    }
   
    // set the URL the request will be made to (implemented by subclasses)
    abstract public function setUrl($url);
     
    // get the given URL
    public function getUrl()
    {
        return $this->_url;
    }
   
    // set the TCP port the request will be made on (implemented by subclasses)
    abstract public function setPort($port);
     
    // get the given port
    public function getPort()
    {
        return $this->_port;
    }
   
    // set the request method (GET or POST)
    public function setMethod($method = ‘GET’)
    {
        $method = strtoupper($method);
        if (!in_array($method, array(‘GET’, ‘POST’), TRUE)) {
            throw new HttpRequestHandlerException(‘The request method is not valid.’);
        }
        $this->_method = $method;
        return $this;
    }
   
    // get the request method
    public function getMethod()
    {
        return $this->_method;
    }
       
    // add a new request header
    public function addHeader($key, $header)
    {
        $key = strtolower($key);
        if (!array_key_exists($key, $this->_headers)) {
            $this->_headers[$key] = $header;
        }
        return $this;
    }
   
    // remove a specified request header
    public function removeHeader($key)
    {
        $key = strtolower($key);
        if (array_key_exists($key, $this->_headers)) {
            unset($this->_headers[$key]);
        }
        return $this;
    }
     
    // get a specified request header
    public function getHeader($key)
    {
        $key = strtolower($key);
        if (array_key_exists($key, $this->_headers)) {
            return $this->_headers[$key];
        }
    }
     
    // get the header included in the response
    public function getResponseHeader()
    {
        return $this->_responseHeader;
    }
   
    // get the content included in the response
    public function getReponseContent()
    {
        return $this->_responseContent;
    }
               
    // send an HTTP request to the specified URL and TCP port
    public function sendRequest()
    {
        // parse and urlencode the request data
        $data = ”;
        foreach ($this->_data as $key => $value) {
            $data .= ‘&’ . $key . ‘=’ . urlencode($value);
        }
        $data = trim($data, ‘&’);
        // parse the given URL
        $url = parse_url($this->_url);
        if (!isset($url['host']) OR !isset($url['path'])) {
            throw new HttpRequestHandlerException(‘No host or path was specified.’);
        }
        $host = $url['host'];
        $path = $url['path'];
        // open a socket connection on the specified TCP port
        if (!$fp = fsockopen($host, $this->_port)) {
            throw new HttpRequestHandlerException(‘Error opening socket connection to the URL ‘. $this->_url . ‘ on port.’ . $this->_port);
        }
        fputs($fp, "$this->_method $path HTTP/1.0rn");
        fputs($fp, "Host: $hostrn");
        fputs($fp, "Content-type: application/x-www-form-urlencodedrn");
        fputs($fp, "Content-length: ". strlen($data) . "rn");
        fputs($fp, "Connection: closernrn");
        fputs($fp, $data);
        // get the response of the request
        $response = ”;
        while(!feof($fp)) {
            $response .= fgets($fp, 128);
        }
        // close the socket connection:
        fclose($fp);
        // process the response
        $response = explode("rnrn", $response, 2);
        $this->_responseHeader = $response[0];
        $this->_responseContent = $response[1];
        return $this->_responseContent;
    }
   
    // send the specified header
    public function sendHeader($key)
    {
        if ($header = $this->getHeader($key)) {
            header($header);
        }
    } 
}

 

(HttpRequestHandlerException.php)

<?php

class HttpRequestHandlerException extends Exception{}

If you haven’t worked with sockets in PHP before, don’t worry; the previous class handles the process transparently behind the scenes through its “sendRequest()” method. Besides, the class implements some getters and mutator methods that allow you, among other things, to set the URL and TCP port on which HTTP requests will be made, which are pretty easy to grasp.

So far, so good. Having defined an abstract parent that triggers HTTP requests to a specific URL on a TCP port, we now need to start building the concrete class responsible for communicating directly with the Closure Compiler Service API. As you’ll see in a moment, the driving logic of this class will be very easy to understand, but to learn how it’ll be created you’ll have to click on the following link and keep reading. 

{mospagebreak title=Interacting with the Closure Compiler API using PHP}

In reality, deriving a concrete subclass from the previous abstract parent capable of talking directly to the Closure Compiler Service API is a straightforward process reduced to overriding some of the parent’s default properties and implementing its abstract “setUrl()” and “setPort()” methods. Period.

To demonstrate the veracity of my claim, here’s the initial definition of this concrete class, which not surprisingly has been called “ClosureCompilerHandler.” Check it out:

(ClosureCompilerHandler.php)

<?php

class ClosureCompilerHandler extends HttpRequestHandlerAbstract
{
    protected $_url = ‘http://closure-compiler.appspot.com/compile';
    protected $_port = 80;
    protected $_method = ‘POST';
    protected $_responseHeader;
    protected $_responseContent;
    protected $_headers = array(
                  ‘js’ => ‘Content-type: text/javascript’,
                  ‘xml’ => ‘Content-type: text/xml’,
                  ‘json’ => ‘Content-type: application/json’
              );
}

Didn’t I tell you that the implementation of this concrete class was easy to achieve? Well, as you can see above, the “ClosureCompilerHandler” simply assigns some values (in this case, they’re constraints) to the default properties declared by its parent, including the URL of the Closure Compiler API, its TCP port (as one might expects, it’s 80), and the three MIME headers used to deliver optimized JavaScript files. That was simple to code and read, wasn’t it?

But wait a minute! To get the “ClosureCompilerHandler” class up and running, it’s necessary to implement the pair of abstract methods declared by its parent. That’s precisely what I plan to show you in the upcoming section.

Final touches for the Closure Compiler handler: two additional methods

As I said earlier, below I included for you the corresponding implementations of the “setUrl()” and “setPort()” methods required by the previous “ClosureCompilerHandler” class. Here they are:

// set the URL of the closure compiler API
public function setUrl($url)
{
    if (strpos(‘http://closure-compiler.appspot.com’, $url) !== 0) {
        throw new HttpRequestHandlerException(‘The specified URL for the closure compiler API is not valid.’);
    }
    $this->_url = $url;
    return $this;
}

// set the TCP port of the closure compiler API (throws an exception, as it’s been already set)
public function setPort($port)
{
    throw new HttpRequestHandlerException(‘The specified TCP port for the closure compiler API has been already set.’);
}

As you can see from the code snippet above, the “setUrl()” method simply checks to see that the entered URL is compliant with the one corresponding to the Closure Compiler API, while its cousin, “setPort(),” throws a custom exception, as obviously the compiler’s TCP port can’t be overridden. Of course, the way that these methods have been implemented can be improved, but for the sake of simplicity and clarity I’m going to keep them that simple.

And now that these methods have been properly defined, here’s how the “ClosureCompilerHandler” class looks after adding them to its definition:

(ClosureCompilerHandler.php)

<?php

class ClosureCompilerHandler extends HttpRequestHandlerAbstract
{
    protected $_url = ‘http://closure-compiler.appspot.com/compile';
    protected $_port = 80;
    protected $_method = ‘POST';
    protected $_responseHeader;
    protected $_responseContent;
    protected $_headers = array(
                  ‘js’ => ‘Content-type: text/javascript’,
                  ‘xml’ => ‘Content-type: text/xml’,
                  ‘json’ => ‘Content-type: application/json’
              ); 
   
    // set the URL of the closure compiler API
    public function setUrl($url)
    {
    if (strpos(‘http://closure-compiler.appspot.com’, $url) !== 0) {
        throw new HttpRequestHandlerException(‘The specified URL for the closure compiler API is not valid.’);
    }
    $this->_url = $url;
    return $this;
    }

    // set the TCP port of the closure compiler API (throws an exception, as it’s been already set)
    public function setPort($port)
    {
    throw new HttpRequestHandlerException(‘The specified TCP port for the closure compiler API has been already set.’);
    }    
}

Done. At this point, I’ve managed to create a concrete class, whose main (and only) responsibility is to interact with the Closure Compiler Service API. This is, obviously, a great breakthrough, as the existence of this class will make it extremely easy to optimize JavaScript files through the aforementioned API.

Nevertheless, the full details concerning the execution of the entire optimization process will be discussed in the forthcoming installment of the series. 

Final thoughts

In this second chapter of the series, I went through the development of a concrete PHP class derived from the abstract parent defined in the previous tutorial. As you just saw, it implements some refined methods that permit you to interact “face-to-face” with Google’s Closure Compiler Service API in a pretty straightforward fashion.

With this subclass already up and running, the next step we must take is to start demonstrating how to use it for optimizing JavaScript code programmatically via the pertinent API. Therefore, in the upcoming part of the series I’m going to create a basic example that will show you how to accomplish this in a few simple steps.

Don’t miss the next tutorial!

[gp-comments width="770" linklove="off" ]

chat sex hikayeleri Ensest hikaye