- 2011/12/27

Syntax highlighting is a must for me on every article related to web scripting and contain sample code, it makes me or user easier to read the snippet than usual html tag <pre><code>. Here I show you my way to get snippet code hosted on Gist, and display it on Zend Framework blog application. I use Controller Plugin to get body element of response’s text, and search any gist tag ([gist]{GIST_ID}[/gist]), if any valid gist tag founded, it will replaced with div data from gist’s json response directly and save it as Zend_Cache_Core object.

Here is ControllerPlugin snippet I used on this site :

<?php
/**
 * Simukti_Controller_Plugin_Gist
 */
 
/**
 * ID gist CANNOT contain any whitespace : 
 * Sample Public Gist : [gist]1213734[/gist],
 * Sample Private Gist : [gist]1213fag734[/gist], 
 * 
 * @author Sarjono Mukti Aji
 * @copyright Copyright (c) 2011 - Sarjono Mukti Aji <[email protected]>
 */
class Simukti_Controller_Plugin_Gist extends Zend_Controller_Plugin_Abstract
{
    const GIST_HOST = 'https://gist.github.com/';
 
    /**
     * @param Zend_Controller_Request_Abstract $request
     * @return Zend_Controller_Response_Abstract
     * @see Zend_Controller_Plugin_Abstract::postDispatch()
     */
    public function postDispatch(Zend_Controller_Request_Abstract $request)
    {
        if (! $request->isDispatched()) {
            return;
        }
        
        $frontController = Zend_Controller_Front::getInstance();
        $frontController->unregisterPlugin($this);
        
        $response = $this->getResponse();
        $content  = $response->getBody();
        
        // 0-9a-z for private gist, 0-9 for public gist
        $regex   = '/\[gist\]([0-9a-z]+)\[\/gist\]/';
        $matches = array();
        
        preg_match_all($regex, $content, $matches);
        
        $matchCount = count($matches[0]);
        if(! $matchCount) {
            return;
        }
        
        /**
         * Lets assume that you have set cachemanager template named 'rest' 
         * 
         * @see Zend_Cache_Manager::setCacheTemplate()
         */
        $cache = $frontController->getParam('bootstrap')
                                 ->getResource('cachemanager')
                                 ->getCache('rest');
        
        $client = Zend_Service_Abstract::getHttpClient();
        
        for($i = 0; $i < $matchCount; ++$i) {
            $gistTag = $matches[0][$i];
            $gistId  = $matches[1][$i];
            $gistUrl = self::GIST_HOST . $gistId . '.json';
            $remote  = $client->setUri($gistUrl);
            
            if (null !== $cache) {
                $cacheId  = 'gist_' . $gistId;
                $gistData = $cache->load($cacheId);
            }
            
            if(! isset($gistData) || false === $gistData) {
                /**
                 * It happen once
                 */
                $process = $remote->request(Zend_Http_Client::GET);
                $status  = $process->getStatus();
                
                if($status !== 200) {
                    $gistData = sprintf("<strong>WRONG GIST ID : %s</strong>", $gistId);
                } else {
                    $result   = Zend_Json::decode($process->getBody());
                    $gistData = $result['div'];
                }
                
                if (null !== $cache) {
                    $cache->save($gistData, $cacheId);
                }
            }
            $content  = str_replace($gistTag, $gistData, $content);
        }
        
        $view  = $frontController->getParam('bootstrap')
                                 ->getResource('view');
        $headLink = $view->getHelper('headLink');
        // inject embed stylesheet on the <head>
        $headLink->appendStylesheet(self::GIST_HOST . 'stylesheets/gist/embed.css');
        
        $this->getResponse()->setBody($content);
    }
}

Now you have to register these controller plugin to application bootstrap, or module bootstrap, or in per-controller action.